mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Merge branch 'testnet' into accelerator
This commit is contained in:
commit
13a3622596
150 changed files with 10017 additions and 4491 deletions
19
.github/workflows/build-ton-wasm-emscripten.yml
vendored
19
.github/workflows/build-ton-wasm-emscripten.yml
vendored
|
@ -25,6 +25,25 @@ jobs:
|
||||||
chmod +x fift-func-wasm-build-ubuntu.sh
|
chmod +x fift-func-wasm-build-ubuntu.sh
|
||||||
./fift-func-wasm-build-ubuntu.sh -a
|
./fift-func-wasm-build-ubuntu.sh -a
|
||||||
|
|
||||||
|
- name: Prepare test
|
||||||
|
run: |
|
||||||
|
cp assembly/wasm/*.fc .
|
||||||
|
git clone https://github.com/ton-community/func-js.git
|
||||||
|
cd func-js
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
npm link
|
||||||
|
|
||||||
|
- name: Test TON WASM artifacts
|
||||||
|
run: |
|
||||||
|
base64 -w 0 artifacts/funcfiftlib.wasm > artifacts/funcfiftlib.wasm.js
|
||||||
|
printf "module.exports = { FuncFiftLibWasm: '" | cat - artifacts/funcfiftlib.wasm.js > temp.txt && mv temp.txt artifacts/funcfiftlib.wasm.js
|
||||||
|
echo "'}" >> artifacts/funcfiftlib.wasm.js
|
||||||
|
cp artifacts/funcfiftlib.wasm.js func-js/node_modules/@ton-community/func-js-bin/dist/funcfiftlib.wasm.js
|
||||||
|
cp artifacts/funcfiftlib.js func-js/node_modules/@ton-community/func-js-bin/dist/funcfiftlib.js
|
||||||
|
npx func-js stdlib.fc intrinsics.fc --fift ./output.f
|
||||||
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@master
|
uses: actions/upload-artifact@master
|
||||||
with:
|
with:
|
||||||
|
|
12
.github/workflows/create-release.yml
vendored
12
.github/workflows/create-release.yml
vendored
|
@ -17,6 +17,7 @@ jobs:
|
||||||
workflow: build-ton-linux-arm64-appimage.yml
|
workflow: build-ton-linux-arm64-appimage.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Download and unzip Linux arm64 artifacts
|
- name: Download and unzip Linux arm64 artifacts
|
||||||
|
@ -25,6 +26,7 @@ jobs:
|
||||||
workflow: build-ton-linux-arm64-appimage.yml
|
workflow: build-ton-linux-arm64-appimage.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: false
|
skip_unpack: false
|
||||||
|
|
||||||
- name: Download Linux x86-64 artifacts
|
- name: Download Linux x86-64 artifacts
|
||||||
|
@ -33,6 +35,7 @@ jobs:
|
||||||
workflow: build-ton-linux-x86-64-appimage.yml
|
workflow: build-ton-linux-x86-64-appimage.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Download and unzip Linux x86-64 artifacts
|
- name: Download and unzip Linux x86-64 artifacts
|
||||||
|
@ -41,6 +44,7 @@ jobs:
|
||||||
workflow: build-ton-linux-x86-64-appimage.yml
|
workflow: build-ton-linux-x86-64-appimage.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: false
|
skip_unpack: false
|
||||||
|
|
||||||
- name: Download Mac x86-64 artifacts
|
- name: Download Mac x86-64 artifacts
|
||||||
|
@ -49,6 +53,7 @@ jobs:
|
||||||
workflow: build-ton-macos-13-x86-64-portable.yml
|
workflow: build-ton-macos-13-x86-64-portable.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Download Mac arm64 artifacts
|
- name: Download Mac arm64 artifacts
|
||||||
|
@ -57,6 +62,7 @@ jobs:
|
||||||
workflow: build-ton-macos-14-arm64-portable.yml
|
workflow: build-ton-macos-14-arm64-portable.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Download and unzip Mac x86-64 artifacts
|
- name: Download and unzip Mac x86-64 artifacts
|
||||||
|
@ -65,6 +71,7 @@ jobs:
|
||||||
workflow: build-ton-macos-13-x86-64-portable.yml
|
workflow: build-ton-macos-13-x86-64-portable.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: false
|
skip_unpack: false
|
||||||
|
|
||||||
- name: Download and unzip arm64 artifacts
|
- name: Download and unzip arm64 artifacts
|
||||||
|
@ -73,6 +80,7 @@ jobs:
|
||||||
workflow: build-ton-macos-14-arm64-portable.yml
|
workflow: build-ton-macos-14-arm64-portable.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: false
|
skip_unpack: false
|
||||||
|
|
||||||
- name: Download Windows artifacts
|
- name: Download Windows artifacts
|
||||||
|
@ -81,6 +89,7 @@ jobs:
|
||||||
workflow: ton-x86-64-windows.yml
|
workflow: ton-x86-64-windows.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Download and unzip Windows artifacts
|
- name: Download and unzip Windows artifacts
|
||||||
|
@ -89,6 +98,7 @@ jobs:
|
||||||
workflow: ton-x86-64-windows.yml
|
workflow: ton-x86-64-windows.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: false
|
skip_unpack: false
|
||||||
|
|
||||||
- name: Download WASM artifacts
|
- name: Download WASM artifacts
|
||||||
|
@ -97,6 +107,7 @@ jobs:
|
||||||
workflow: build-ton-wasm-emscripten.yml
|
workflow: build-ton-wasm-emscripten.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Download Android Tonlib artifacts
|
- name: Download Android Tonlib artifacts
|
||||||
|
@ -105,6 +116,7 @@ jobs:
|
||||||
workflow: build-ton-linux-android-tonlib.yml
|
workflow: build-ton-linux-android-tonlib.yml
|
||||||
path: artifacts
|
path: artifacts
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
skip_unpack: true
|
skip_unpack: true
|
||||||
|
|
||||||
- name: Show all artifacts
|
- name: Show all artifacts
|
||||||
|
|
154
.github/workflows/create-tolk-release.yml
vendored
Normal file
154
.github/workflows/create-tolk-release.yml
vendored
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
name: Create tolk release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: 'tolk release and tag name'
|
||||||
|
required: true
|
||||||
|
|
||||||
|
permissions: write-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
create-release:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Download and unzip Linux arm64 artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v6
|
||||||
|
with:
|
||||||
|
workflow: build-ton-linux-arm64-appimage.yml
|
||||||
|
path: artifacts
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
skip_unpack: false
|
||||||
|
|
||||||
|
- name: Download and unzip Linux x86-64 artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v6
|
||||||
|
with:
|
||||||
|
workflow: build-ton-linux-x86-64-appimage.yml
|
||||||
|
path: artifacts
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
skip_unpack: false
|
||||||
|
|
||||||
|
- name: Download and unzip Mac x86-64 artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v6
|
||||||
|
with:
|
||||||
|
workflow: build-ton-macos-13-x86-64-portable.yml
|
||||||
|
path: artifacts
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
skip_unpack: false
|
||||||
|
|
||||||
|
- name: Download and unzip arm64 artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v6
|
||||||
|
with:
|
||||||
|
workflow: build-ton-macos-14-arm64-portable.yml
|
||||||
|
path: artifacts
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
skip_unpack: false
|
||||||
|
|
||||||
|
- name: Download and unzip Windows artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v6
|
||||||
|
with:
|
||||||
|
workflow: ton-x86-64-windows.yml
|
||||||
|
path: artifacts
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
skip_unpack: false
|
||||||
|
|
||||||
|
- name: Download WASM artifacts
|
||||||
|
uses: dawidd6/action-download-artifact@v6
|
||||||
|
with:
|
||||||
|
workflow: build-ton-wasm-emscripten.yml
|
||||||
|
path: artifacts
|
||||||
|
workflow_conclusion: success
|
||||||
|
branch: master
|
||||||
|
skip_unpack: true
|
||||||
|
|
||||||
|
- name: Show all artifacts
|
||||||
|
run: |
|
||||||
|
tree artifacts
|
||||||
|
|
||||||
|
|
||||||
|
# create release
|
||||||
|
- name: Get registration token
|
||||||
|
id: getRegToken
|
||||||
|
run: |
|
||||||
|
curl -X POST -H \"Accept: application/vnd.github+json\" -H 'Authorization: token ${{ secrets.GITHUB_TOKEN }}' https://api.github.com/repos/ton-blockchain/ton/actions/runners/registration-token
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ inputs.tag }}
|
||||||
|
release_name: ${{ inputs.tag }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
# upload
|
||||||
|
|
||||||
|
# win
|
||||||
|
|
||||||
|
- name: Upload Windows 2019 single artifact - tolk
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: artifacts/ton-x86-64-windows/tolk.exe
|
||||||
|
asset_name: tolk.exe
|
||||||
|
tag: ${{ inputs.tag }}
|
||||||
|
|
||||||
|
# mac x86-64
|
||||||
|
|
||||||
|
- name: Upload Mac x86-64 single artifact - tolk
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: artifacts/ton-x86_64-macos/tolk
|
||||||
|
asset_name: tolk-mac-x86-64
|
||||||
|
tag: ${{ inputs.tag }}
|
||||||
|
|
||||||
|
# mac arm64
|
||||||
|
|
||||||
|
- name: Upload Mac arm64 single artifact - tolk
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: artifacts/ton-arm64-macos/tolk
|
||||||
|
asset_name: tolk-mac-arm64
|
||||||
|
tag: ${{ inputs.tag }}
|
||||||
|
|
||||||
|
# linux x86-64
|
||||||
|
|
||||||
|
- name: Upload Linux x86-64 single artifact - tolk
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: artifacts/ton-x86_64-linux/tolk
|
||||||
|
asset_name: tolk-linux-x86_64
|
||||||
|
tag: ${{ inputs.tag }}
|
||||||
|
|
||||||
|
# linux arm64
|
||||||
|
|
||||||
|
- name: Upload Linux arm64 single artifact - tolk
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: artifacts/ton-arm64-linux/tolk
|
||||||
|
asset_name: tolk-linux-arm64
|
||||||
|
tag: ${{ inputs.tag }}
|
||||||
|
|
||||||
|
- name: Upload WASM artifacts
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: artifacts/ton-wasm.zip
|
||||||
|
asset_name: ton-wasm.zip
|
||||||
|
tag: ${{ inputs.tag }}
|
||||||
|
|
|
@ -47,9 +47,9 @@ Main TON monorepo, which includes the code of the node/validator, lite-client, t
|
||||||
__The Open Network (TON)__ is a fast, secure, scalable blockchain focused on handling _millions of transactions per second_ (TPS) with the goal of reaching hundreds of millions of blockchain users.
|
__The Open Network (TON)__ is a fast, secure, scalable blockchain focused on handling _millions of transactions per second_ (TPS) with the goal of reaching hundreds of millions of blockchain users.
|
||||||
- To learn more about different aspects of TON blockchain and its underlying ecosystem check [documentation](https://ton.org/docs)
|
- To learn more about different aspects of TON blockchain and its underlying ecosystem check [documentation](https://ton.org/docs)
|
||||||
- To run node, validator or lite-server check [Participate section](https://ton.org/docs/participate/nodes/run-node)
|
- To run node, validator or lite-server check [Participate section](https://ton.org/docs/participate/nodes/run-node)
|
||||||
- To develop decentralised apps check [Tutorials](https://ton.org/docs/develop/smart-contracts/), [FunC docs](https://ton.org/docs/develop/func/overview) and [DApp tutorials](https://ton.org/docs/develop/dapps/)
|
- To develop decentralised apps check [Tutorials](https://docs.ton.org/v3/guidelines/smart-contracts/guidelines), [FunC docs](https://ton.org/docs/develop/func/overview) and [DApp tutorials](https://docs.ton.org/v3/guidelines/dapps/overview)
|
||||||
- To work on TON check [wallets](https://ton.app/wallets), [explorers](https://ton.app/explorers), [DEXes](https://ton.app/dex) and [utilities](https://ton.app/utilities)
|
- To work on TON check [wallets](https://ton.app/wallets), [explorers](https://ton.app/explorers), [DEXes](https://ton.app/dex) and [utilities](https://ton.app/utilities)
|
||||||
- To interact with TON check [APIs](https://ton.org/docs/develop/dapps/apis/)
|
- To interact with TON check [APIs](https://docs.ton.org/v3/guidelines/dapps/apis-sdks/overview)
|
||||||
|
|
||||||
## Updates flow
|
## Updates flow
|
||||||
|
|
||||||
|
|
|
@ -71,8 +71,8 @@ echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd emsdk
|
cd emsdk
|
||||||
./emsdk install 3.1.40
|
./emsdk install 3.1.19
|
||||||
./emsdk activate 3.1.40
|
./emsdk activate 3.1.19
|
||||||
EMSDK_DIR=`pwd`
|
EMSDK_DIR=`pwd`
|
||||||
|
|
||||||
. $EMSDK_DIR/emsdk_env.sh
|
. $EMSDK_DIR/emsdk_env.sh
|
||||||
|
|
61
assembly/wasm/intrinsics.fc
Normal file
61
assembly/wasm/intrinsics.fc
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#pragma allow-post-modification;
|
||||||
|
#pragma compute-asm-ltr;
|
||||||
|
|
||||||
|
(slice, slice) __tact_load_address(slice cs) inline {
|
||||||
|
slice raw = cs~load_msg_addr();
|
||||||
|
return (cs, raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
slice __gen_slice1 () asm """
|
||||||
|
B{b5ee9c72410101010005000006abcdefe1e98884} B>boc <s PUSHSLICE
|
||||||
|
""";
|
||||||
|
|
||||||
|
slice __gen_slice_slice_eb58904b617945cdf4f33042169c462cd36cf1772a2229f06171fd899e920b7f() asm """
|
||||||
|
B{b5ee9c724101010100030000011025086565} B>boc <s PUSHSLICE
|
||||||
|
""";
|
||||||
|
|
||||||
|
slice __gen_slice3 () asm """
|
||||||
|
B{b5ee9c724101010100030000017888c37a8e} B>boc <s PUSHSLICE
|
||||||
|
""";
|
||||||
|
|
||||||
|
slice __gen_slice_slice_6694a4a61b0dc7c7d5f63bbd394449f6921de7b2ad9cb() asm """
|
||||||
|
B{b5ee9c724101010100820000ffabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdab} B>boc <s PUSHSLICE
|
||||||
|
""";
|
||||||
|
|
||||||
|
slice __gen_slice_slice_80b26bab85f37e2bde3795993cdf7402cd42e68eff6187e8388083ce6cfe7c92() asm """
|
||||||
|
B{b5ee9c724101010100030000018a0adc2f9c} B>boc <s PUSHSLICE
|
||||||
|
""";
|
||||||
|
|
||||||
|
|
||||||
|
(slice,((slice, cell, int, int, slice, slice, int, int, int, int, slice, slice, slice, slice, slice, slice, slice, slice, slice, slice, slice))) IntrinsicsTester_load(slice sc_0) inline {
|
||||||
|
var v'c = sc_0~__tact_load_address();
|
||||||
|
var v'd = sc_0~load_ref();
|
||||||
|
var v'e = sc_0~load_int(257);
|
||||||
|
var v'f = sc_0~load_int(257);
|
||||||
|
slice sc_1 = sc_0~load_ref().begin_parse();
|
||||||
|
var v'g = sc_1~load_ref().begin_parse();
|
||||||
|
var v'h = sc_1~load_ref().begin_parse();
|
||||||
|
var v'i = sc_1~load_int(257);
|
||||||
|
var v'j = sc_1~load_int(257);
|
||||||
|
var v'k = sc_1~load_int(257);
|
||||||
|
slice sc_2 = sc_1~load_ref().begin_parse();
|
||||||
|
var v'l = sc_2~load_int(257);
|
||||||
|
var v'm = sc_2~load_ref().begin_parse();
|
||||||
|
var v'n = sc_2~load_ref().begin_parse();
|
||||||
|
var v'o = sc_2~load_ref().begin_parse();
|
||||||
|
slice sc_3 = sc_2~load_ref().begin_parse();
|
||||||
|
var v'p = sc_3~load_ref().begin_parse();
|
||||||
|
var v'q = sc_3~load_ref().begin_parse();
|
||||||
|
var v'r = sc_3~load_ref().begin_parse();
|
||||||
|
slice sc_4 = sc_3~load_ref().begin_parse();
|
||||||
|
var v's = sc_4~load_ref().begin_parse();
|
||||||
|
var v't = sc_4~load_ref().begin_parse();
|
||||||
|
var v'u = sc_4~load_ref().begin_parse();
|
||||||
|
slice sc_5 = sc_4~load_ref().begin_parse();
|
||||||
|
var v'w = sc_5~load_ref().begin_parse();
|
||||||
|
var v'v = sc_5~load_ref().begin_parse();
|
||||||
|
return (sc_0, (v'c, v'd, v'e, v'f, v'g, v'h, v'i, v'j, v'k, v'l, v'm, v'n, v'o, v'p, v'q, v'r, v's, v't, v'u, v'w, v'v));
|
||||||
|
}
|
||||||
|
|
||||||
|
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { }
|
||||||
|
|
681
assembly/wasm/stdlib.fc
Normal file
681
assembly/wasm/stdlib.fc
Normal file
|
@ -0,0 +1,681 @@
|
||||||
|
;; Standard library for funC
|
||||||
|
;;
|
||||||
|
|
||||||
|
{-
|
||||||
|
This file is part of TON FunC Standard Library.
|
||||||
|
|
||||||
|
FunC Standard Library is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
FunC Standard Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
-}
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Tuple manipulation primitives
|
||||||
|
The names and the types are mostly self-explaining.
|
||||||
|
See [polymorhism with forall](https://ton.org/docs/#/func/functions?id=polymorphism-with-forall)
|
||||||
|
for more info on the polymorphic functions.
|
||||||
|
|
||||||
|
Note that currently values of atomic type `tuple` can't be cast to composite tuple type (e.g. `[int, cell]`)
|
||||||
|
and vise versa.
|
||||||
|
-}
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Lisp-style lists
|
||||||
|
|
||||||
|
Lists can be represented as nested 2-elements tuples.
|
||||||
|
Empty list is conventionally represented as TVM `null` value (it can be obtained by calling [null()]).
|
||||||
|
For example, tuple `(1, (2, (3, null)))` represents list `[1, 2, 3]`. Elements of a list can be of different types.
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Adds an element to the beginning of lisp-style list.
|
||||||
|
forall X -> tuple cons(X head, tuple tail) asm "CONS";
|
||||||
|
|
||||||
|
;;; Extracts the head and the tail of lisp-style list.
|
||||||
|
forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";
|
||||||
|
|
||||||
|
;;; Extracts the tail and the head of lisp-style list.
|
||||||
|
forall X -> (tuple, X) list_next(tuple list) asm(-> 1 0) "UNCONS";
|
||||||
|
|
||||||
|
;;; Returns the head of lisp-style list.
|
||||||
|
forall X -> X car(tuple list) asm "CAR";
|
||||||
|
|
||||||
|
;;; Returns the tail of lisp-style list.
|
||||||
|
tuple cdr(tuple list) asm "CDR";
|
||||||
|
|
||||||
|
;;; Creates tuple with zero elements.
|
||||||
|
tuple empty_tuple() asm "NIL";
|
||||||
|
|
||||||
|
;;; Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)`
|
||||||
|
;;; is of length at most 255. Otherwise throws a type check exception.
|
||||||
|
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
|
||||||
|
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
|
||||||
|
|
||||||
|
;;; Creates a tuple of length one with given argument as element.
|
||||||
|
forall X -> [X] single(X x) asm "SINGLE";
|
||||||
|
|
||||||
|
;;; Unpacks a tuple of length one
|
||||||
|
forall X -> X unsingle([X] t) asm "UNSINGLE";
|
||||||
|
|
||||||
|
;;; Creates a tuple of length two with given arguments as elements.
|
||||||
|
forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR";
|
||||||
|
|
||||||
|
;;; Unpacks a tuple of length two
|
||||||
|
forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR";
|
||||||
|
|
||||||
|
;;; Creates a tuple of length three with given arguments as elements.
|
||||||
|
forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE";
|
||||||
|
|
||||||
|
;;; Unpacks a tuple of length three
|
||||||
|
forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE";
|
||||||
|
|
||||||
|
;;; Creates a tuple of length four with given arguments as elements.
|
||||||
|
forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE";
|
||||||
|
|
||||||
|
;;; Unpacks a tuple of length four
|
||||||
|
forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE";
|
||||||
|
|
||||||
|
;;; Returns the first element of a tuple (with unknown element types).
|
||||||
|
forall X -> X first(tuple t) asm "FIRST";
|
||||||
|
|
||||||
|
;;; Returns the second element of a tuple (with unknown element types).
|
||||||
|
forall X -> X second(tuple t) asm "SECOND";
|
||||||
|
|
||||||
|
;;; Returns the third element of a tuple (with unknown element types).
|
||||||
|
forall X -> X third(tuple t) asm "THIRD";
|
||||||
|
|
||||||
|
;;; Returns the fourth element of a tuple (with unknown element types).
|
||||||
|
forall X -> X fourth(tuple t) asm "3 INDEX";
|
||||||
|
|
||||||
|
;;; Returns the first element of a pair tuple.
|
||||||
|
forall X, Y -> X pair_first([X, Y] p) asm "FIRST";
|
||||||
|
|
||||||
|
;;; Returns the second element of a pair tuple.
|
||||||
|
forall X, Y -> Y pair_second([X, Y] p) asm "SECOND";
|
||||||
|
|
||||||
|
;;; Returns the first element of a triple tuple.
|
||||||
|
forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST";
|
||||||
|
|
||||||
|
;;; Returns the second element of a triple tuple.
|
||||||
|
forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";
|
||||||
|
|
||||||
|
;;; Returns the third element of a triple tuple.
|
||||||
|
forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD";
|
||||||
|
|
||||||
|
|
||||||
|
;;; Push null element (casted to given type)
|
||||||
|
;;; By the TVM type `Null` FunC represents absence of a value of some atomic type.
|
||||||
|
;;; So `null` can actually have any atomic type.
|
||||||
|
forall X -> X null() asm "PUSHNULL";
|
||||||
|
|
||||||
|
;;; Moves a variable [x] to the top of the stack
|
||||||
|
forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;;; Returns the current Unix time as an Integer
|
||||||
|
int now() asm "NOW";
|
||||||
|
|
||||||
|
;;; Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`.
|
||||||
|
;;; If necessary, it can be parsed further using primitives such as [parse_std_addr].
|
||||||
|
slice my_address() asm "MYADDR";
|
||||||
|
|
||||||
|
;;; Returns the balance of the smart contract as a tuple consisting of an int
|
||||||
|
;;; (balance in nanotoncoins) and a `cell`
|
||||||
|
;;; (a dictionary with 32-bit keys representing the balance of "extra currencies")
|
||||||
|
;;; at the start of Computation Phase.
|
||||||
|
;;; Note that RAW primitives such as [send_raw_message] do not update this field.
|
||||||
|
[int, cell] get_balance() asm "BALANCE";
|
||||||
|
|
||||||
|
;;; Returns the logical time of the current transaction.
|
||||||
|
int cur_lt() asm "LTIME";
|
||||||
|
|
||||||
|
;;; Returns the starting logical time of the current block.
|
||||||
|
int block_lt() asm "BLOCKLT";
|
||||||
|
|
||||||
|
;;; Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`.
|
||||||
|
;;; Useful for signing and checking signatures of arbitrary entities represented by a tree of cells.
|
||||||
|
int cell_hash(cell c) asm "HASHCU";
|
||||||
|
|
||||||
|
;;; Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`.
|
||||||
|
;;; The result is the same as if an ordinary cell containing only data and references from `s` had been created
|
||||||
|
;;; and its hash computed by [cell_hash].
|
||||||
|
int slice_hash(slice s) asm "HASHSU";
|
||||||
|
|
||||||
|
;;; Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight,
|
||||||
|
;;; throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`.
|
||||||
|
int string_hash(slice s) asm "SHA256U";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Signature checks
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data)
|
||||||
|
;;; using [public_key] (also represented by a 256-bit unsigned integer).
|
||||||
|
;;; The signature must contain at least 512 data bits; only the first 512 bits are used.
|
||||||
|
;;; The result is `−1` if the signature is valid, `0` otherwise.
|
||||||
|
;;; Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`.
|
||||||
|
;;; That is, if [hash] is computed as the hash of some data, these data are hashed twice,
|
||||||
|
;;; the second hashing occurring inside `CHKSIGNS`.
|
||||||
|
int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU";
|
||||||
|
|
||||||
|
;;; Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`,
|
||||||
|
;;; similarly to [check_signature].
|
||||||
|
;;; If the bit length of [data] is not divisible by eight, throws a cell underflow exception.
|
||||||
|
;;; The verification of Ed25519 signatures is the standard one,
|
||||||
|
;;; with sha256 used to reduce [data] to the 256-bit number that is actually signed.
|
||||||
|
int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS";
|
||||||
|
|
||||||
|
{---
|
||||||
|
# Computation of boc size
|
||||||
|
The primitives below may be useful for computing storage fees of user-provided data.
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Returns `(x, y, z, -1)` or `(null, null, null, 0)`.
|
||||||
|
;;; Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z`
|
||||||
|
;;; in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account
|
||||||
|
;;; the identification of equal cells.
|
||||||
|
;;; The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG,
|
||||||
|
;;; with a hash table of visited cell hashes used to prevent visits of already-visited cells.
|
||||||
|
;;; The total count of visited cells `x` cannot exceed non-negative [max_cells];
|
||||||
|
;;; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and
|
||||||
|
;;; a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`.
|
||||||
|
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
|
||||||
|
|
||||||
|
;;; Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`.
|
||||||
|
;;; The returned value of `x` does not take into account the cell that contains the `slice` [s] itself;
|
||||||
|
;;; however, the data bits and the cell references of [s] are accounted for in `y` and `z`.
|
||||||
|
(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE";
|
||||||
|
|
||||||
|
;;; A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure.
|
||||||
|
(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||||
|
|
||||||
|
;;; A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure.
|
||||||
|
(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||||
|
|
||||||
|
;;; Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator)
|
||||||
|
;; () throw_if(int excno, int cond) impure asm "THROWARGIF";
|
||||||
|
|
||||||
|
{--
|
||||||
|
# Debug primitives
|
||||||
|
Only works for local TVM execution with debug level verbosity
|
||||||
|
-}
|
||||||
|
;;; Dumps the stack (at most the top 255 values) and shows the total stack depth.
|
||||||
|
() dump_stack() impure asm "DUMPSTK";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Persistent storage save and load
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later.
|
||||||
|
cell get_data() asm "c4 PUSH";
|
||||||
|
|
||||||
|
;;; Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive.
|
||||||
|
() set_data(cell c) impure asm "c4 POP";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Continuation primitives
|
||||||
|
-}
|
||||||
|
;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.
|
||||||
|
;;; The primitive returns the current value of `c3`.
|
||||||
|
cont get_c3() impure asm "c3 PUSH";
|
||||||
|
|
||||||
|
;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time.
|
||||||
|
;;; Note that after execution of this primitive the current code
|
||||||
|
;;; (and the stack of recursive function calls) won't change,
|
||||||
|
;;; but any other function call will use a function from the new code.
|
||||||
|
() set_c3(cont c) impure asm "c3 POP";
|
||||||
|
|
||||||
|
;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist.
|
||||||
|
cont bless(slice s) impure asm "BLESS";
|
||||||
|
|
||||||
|
{---
|
||||||
|
# Gas related primitives
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero,
|
||||||
|
;;; decreasing the value of `gr` by `gc` in the process.
|
||||||
|
;;; In other words, the current smart contract agrees to buy some gas to finish the current transaction.
|
||||||
|
;;; This action is required to process external messages, which bring no value (hence no gas) with themselves.
|
||||||
|
;;;
|
||||||
|
;;; For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept).
|
||||||
|
() accept_message() impure asm "ACCEPT";
|
||||||
|
|
||||||
|
;;; Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero.
|
||||||
|
;;; If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`,
|
||||||
|
;;; an (unhandled) out of gas exception is thrown before setting new gas limits.
|
||||||
|
;;; Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message].
|
||||||
|
() set_gas_limit(int limit) impure asm "SETGASLIMIT";
|
||||||
|
|
||||||
|
;;; Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”)
|
||||||
|
;;; so that the current execution is considered “successful” with the saved values even if an exception
|
||||||
|
;;; in Computation Phase is thrown later.
|
||||||
|
() commit() impure asm "COMMIT";
|
||||||
|
|
||||||
|
;;; Not implemented
|
||||||
|
;;; Computes the amount of gas that can be bought for `amount` nanoTONs,
|
||||||
|
;;; and sets `gl` accordingly in the same way as [set_gas_limit].
|
||||||
|
;;() buy_gas(int amount) impure asm "BUYGAS";
|
||||||
|
|
||||||
|
;;; Computes the minimum of two integers [x] and [y].
|
||||||
|
int min(int x, int y) asm "MIN";
|
||||||
|
|
||||||
|
;;; Computes the maximum of two integers [x] and [y].
|
||||||
|
int max(int x, int y) asm "MAX";
|
||||||
|
|
||||||
|
;;; Sorts two integers.
|
||||||
|
(int, int) minmax(int x, int y) asm "MINMAX";
|
||||||
|
|
||||||
|
;;; Computes the absolute value of an integer [x].
|
||||||
|
int abs(int x) asm "ABS";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Slice primitives
|
||||||
|
|
||||||
|
It is said that a primitive _loads_ some data,
|
||||||
|
if it returns the data and the remainder of the slice
|
||||||
|
(so it can also be used as [modifying method](https://ton.org/docs/#/func/statements?id=modifying-methods)).
|
||||||
|
|
||||||
|
It is said that a primitive _preloads_ some data, if it returns only the data
|
||||||
|
(it can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods)).
|
||||||
|
|
||||||
|
Unless otherwise stated, loading and preloading primitives read the data from a prefix of the slice.
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
;;; Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell,
|
||||||
|
;;; or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2)
|
||||||
|
;;; which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards.
|
||||||
|
slice begin_parse(cell c) asm "CTOS";
|
||||||
|
|
||||||
|
;;; Checks if [s] is empty. If not, throws an exception.
|
||||||
|
() end_parse(slice s) impure asm "ENDS";
|
||||||
|
|
||||||
|
;;; Loads the first reference from the slice.
|
||||||
|
(slice, cell) load_ref(slice s) asm(-> 1 0) "LDREF";
|
||||||
|
|
||||||
|
;;; Preloads the first reference from the slice.
|
||||||
|
cell preload_ref(slice s) asm "PLDREF";
|
||||||
|
|
||||||
|
{- Functions below are commented because are implemented on compilator level for optimisation -}
|
||||||
|
|
||||||
|
;;; Loads a signed [len]-bit integer from a slice [s].
|
||||||
|
;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX";
|
||||||
|
|
||||||
|
;;; Loads an unsigned [len]-bit integer from a slice [s].
|
||||||
|
;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX";
|
||||||
|
|
||||||
|
;;; Preloads a signed [len]-bit integer from a slice [s].
|
||||||
|
;; int preload_int(slice s, int len) asm "PLDIX";
|
||||||
|
|
||||||
|
;;; Preloads an unsigned [len]-bit integer from a slice [s].
|
||||||
|
;; int preload_uint(slice s, int len) asm "PLDUX";
|
||||||
|
|
||||||
|
;;; Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`.
|
||||||
|
;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX";
|
||||||
|
|
||||||
|
;;; Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`.
|
||||||
|
;; slice preload_bits(slice s, int len) asm "PLDSLICEX";
|
||||||
|
|
||||||
|
;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^120 - 1`).
|
||||||
|
(slice, int) load_grams(slice s) asm(-> 1 0) "LDGRAMS";
|
||||||
|
(slice, int) load_coins(slice s) asm(-> 1 0) "LDVARUINT16";
|
||||||
|
|
||||||
|
(slice, int) load_varint16(slice s) asm(-> 1 0) "LDVARINT16";
|
||||||
|
(slice, int) load_varint32(slice s) asm(-> 1 0) "LDVARINT32";
|
||||||
|
(slice, int) load_varuint16(slice s) asm(-> 1 0) "LDVARUINT16";
|
||||||
|
(slice, int) load_varuint32(slice s) asm(-> 1 0) "LDVARUINT32";
|
||||||
|
|
||||||
|
;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||||
|
slice skip_bits(slice s, int len) asm "SDSKIPFIRST";
|
||||||
|
(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST";
|
||||||
|
|
||||||
|
;;; Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||||
|
slice first_bits(slice s, int len) asm "SDCUTFIRST";
|
||||||
|
|
||||||
|
;;; Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||||
|
slice skip_last_bits(slice s, int len) asm "SDSKIPLAST";
|
||||||
|
(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST";
|
||||||
|
|
||||||
|
;;; Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s].
|
||||||
|
slice slice_last(slice s, int len) asm "SDCUTLAST";
|
||||||
|
|
||||||
|
;;; Loads a dictionary `D` (HashMapE) from `slice` [s].
|
||||||
|
;;; (returns `null` if `nothing` constructor is used).
|
||||||
|
(slice, cell) load_dict(slice s) asm(-> 1 0) "LDDICT";
|
||||||
|
|
||||||
|
;;; Preloads a dictionary `D` from `slice` [s].
|
||||||
|
cell preload_dict(slice s) asm "PLDDICT";
|
||||||
|
|
||||||
|
;;; Loads a dictionary as [load_dict], but returns only the remainder of the slice.
|
||||||
|
slice skip_dict(slice s) asm "SKIPDICT";
|
||||||
|
(slice, ()) ~skip_dict(slice s) asm "SKIPDICT";
|
||||||
|
|
||||||
|
;;; Loads (Maybe ^Cell) from `slice` [s].
|
||||||
|
;;; In other words loads 1 bit and if it is true
|
||||||
|
;;; loads first ref and return it with slice remainder
|
||||||
|
;;; otherwise returns `null` and slice remainder
|
||||||
|
(slice, cell) load_maybe_ref(slice s) asm(-> 1 0) "LDOPTREF";
|
||||||
|
|
||||||
|
;;; Preloads (Maybe ^Cell) from `slice` [s].
|
||||||
|
cell preload_maybe_ref(slice s) asm "PLDOPTREF";
|
||||||
|
|
||||||
|
|
||||||
|
;;; Returns the depth of `cell` [c].
|
||||||
|
;;; If [c] has no references, then return `0`;
|
||||||
|
;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [c].
|
||||||
|
;;; If [c] is a `null` instead of a cell, returns zero.
|
||||||
|
int cell_depth(cell c) asm "CDEPTH";
|
||||||
|
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Slice size primitives
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Returns the number of references in `slice` [s].
|
||||||
|
int slice_refs(slice s) asm "SREFS";
|
||||||
|
|
||||||
|
;;; Returns the number of data bits in `slice` [s].
|
||||||
|
int slice_bits(slice s) asm "SBITS";
|
||||||
|
|
||||||
|
;;; Returns both the number of data bits and the number of references in `slice` [s].
|
||||||
|
(int, int) slice_bits_refs(slice s) asm "SBITREFS";
|
||||||
|
|
||||||
|
;;; Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references).
|
||||||
|
int slice_empty?(slice s) asm "SEMPTY";
|
||||||
|
|
||||||
|
;;; Checks whether `slice` [s] has no bits of data.
|
||||||
|
int slice_data_empty?(slice s) asm "SDEMPTY";
|
||||||
|
|
||||||
|
;;; Checks whether `slice` [s] has no references.
|
||||||
|
int slice_refs_empty?(slice s) asm "SREMPTY";
|
||||||
|
|
||||||
|
;;; Returns the depth of `slice` [s].
|
||||||
|
;;; If [s] has no references, then returns `0`;
|
||||||
|
;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [s].
|
||||||
|
int slice_depth(slice s) asm "SDEPTH";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Builder size primitives
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Returns the number of cell references already stored in `builder` [b]
|
||||||
|
int builder_refs(builder b) asm "BREFS";
|
||||||
|
|
||||||
|
;;; Returns the number of data bits already stored in `builder` [b].
|
||||||
|
int builder_bits(builder b) asm "BBITS";
|
||||||
|
|
||||||
|
;;; Returns the depth of `builder` [b].
|
||||||
|
;;; If no cell references are stored in [b], then returns 0;
|
||||||
|
;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [b].
|
||||||
|
int builder_depth(builder b) asm "BDEPTH";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Builder primitives
|
||||||
|
It is said that a primitive _stores_ a value `x` into a builder `b`
|
||||||
|
if it returns a modified version of the builder `b'` with the value `x` stored at the end of it.
|
||||||
|
It can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods).
|
||||||
|
|
||||||
|
All the primitives below first check whether there is enough space in the `builder`,
|
||||||
|
and only then check the range of the value being serialized.
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Creates a new empty `builder`.
|
||||||
|
builder begin_cell() asm "NEWC";
|
||||||
|
|
||||||
|
;;; Converts a `builder` into an ordinary `cell`.
|
||||||
|
cell end_cell(builder b) asm "ENDC";
|
||||||
|
|
||||||
|
;;; Stores a reference to `cell` [c] into `builder` [b].
|
||||||
|
builder store_ref(builder b, cell c) asm(c b) "STREF";
|
||||||
|
|
||||||
|
;;; Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`.
|
||||||
|
;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX";
|
||||||
|
|
||||||
|
;;; Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`.
|
||||||
|
;; builder store_int(builder b, int x, int len) asm(x b len) "STIX";
|
||||||
|
|
||||||
|
|
||||||
|
;;; Stores `slice` [s] into `builder` [b]
|
||||||
|
builder store_slice(builder b, slice s) asm "STSLICER";
|
||||||
|
|
||||||
|
;;; Stores (serializes) an integer [x] in the range `0..2^120 − 1` into `builder` [b].
|
||||||
|
;;; The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`,
|
||||||
|
;;; which is the smallest integer `l ≥ 0`, such that `x < 2^8l`,
|
||||||
|
;;; followed by an `8l`-bit unsigned big-endian representation of [x].
|
||||||
|
;;; If [x] does not belong to the supported range, a range check exception is thrown.
|
||||||
|
;;;
|
||||||
|
;;; Store amounts of TonCoins to the builder as VarUInteger 16
|
||||||
|
builder store_grams(builder b, int x) asm "STGRAMS";
|
||||||
|
builder store_coins(builder b, int x) asm "STVARUINT16";
|
||||||
|
|
||||||
|
builder store_varint16(builder b, int x) asm "STVARINT16";
|
||||||
|
builder store_varint32(builder b, int x) asm "STVARINT32";
|
||||||
|
builder store_varuint16(builder b, int x) asm "STVARUINT16";
|
||||||
|
builder store_varuint32(builder b, int x) asm "STVARUINT32";
|
||||||
|
|
||||||
|
;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b].
|
||||||
|
;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise.
|
||||||
|
builder store_dict(builder b, cell c) asm(c b) "STDICT";
|
||||||
|
|
||||||
|
;;; Stores (Maybe ^Cell) to builder:
|
||||||
|
;;; if cell is null store 1 zero bit
|
||||||
|
;;; otherwise store 1 true bit and ref to cell
|
||||||
|
builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF";
|
||||||
|
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Address manipulation primitives
|
||||||
|
The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme:
|
||||||
|
```TL-B
|
||||||
|
addr_none$00 = MsgAddressExt;
|
||||||
|
addr_extern$01 len:(## 8) external_address:(bits len)
|
||||||
|
= MsgAddressExt;
|
||||||
|
anycast_info$_ depth:(#<= 30) { depth >= 1 }
|
||||||
|
rewrite_pfx:(bits depth) = Anycast;
|
||||||
|
addr_std$10 anycast:(Maybe Anycast)
|
||||||
|
workchain_id:int8 address:bits256 = MsgAddressInt;
|
||||||
|
addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
|
||||||
|
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
|
||||||
|
_ _:MsgAddressInt = MsgAddress;
|
||||||
|
_ _:MsgAddressExt = MsgAddress;
|
||||||
|
|
||||||
|
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
|
||||||
|
src:MsgAddress dest:MsgAddressInt
|
||||||
|
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
|
||||||
|
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;
|
||||||
|
ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt
|
||||||
|
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;
|
||||||
|
```
|
||||||
|
A deserialized `MsgAddress` is represented by a tuple `t` as follows:
|
||||||
|
|
||||||
|
- `addr_none` is represented by `t = (0)`,
|
||||||
|
i.e., a tuple containing exactly one integer equal to zero.
|
||||||
|
- `addr_extern` is represented by `t = (1, s)`,
|
||||||
|
where slice `s` contains the field `external_address`. In other words, `
|
||||||
|
t` is a pair (a tuple consisting of two entries), containing an integer equal to one and slice `s`.
|
||||||
|
- `addr_std` is represented by `t = (2, u, x, s)`,
|
||||||
|
where `u` is either a `null` (if `anycast` is absent) or a slice `s'` containing `rewrite_pfx` (if anycast is present).
|
||||||
|
Next, integer `x` is the `workchain_id`, and slice `s` contains the address.
|
||||||
|
- `addr_var` is represented by `t = (3, u, x, s)`,
|
||||||
|
where `u`, `x`, and `s` have the same meaning as for `addr_std`.
|
||||||
|
-}
|
||||||
|
|
||||||
|
;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`,
|
||||||
|
;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices.
|
||||||
|
(slice, slice) load_msg_addr(slice s) asm(-> 1 0) "LDMSGADDR";
|
||||||
|
|
||||||
|
;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`.
|
||||||
|
;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown.
|
||||||
|
tuple parse_addr(slice s) asm "PARSEMSGADDR";
|
||||||
|
|
||||||
|
;;; Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`),
|
||||||
|
;;; applies rewriting from the anycast (if present) to the same-length prefix of the address,
|
||||||
|
;;; and returns both the workchain and the 256-bit address as integers.
|
||||||
|
;;; If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`,
|
||||||
|
;;; throws a cell deserialization exception.
|
||||||
|
(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR";
|
||||||
|
|
||||||
|
;;; A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s],
|
||||||
|
;;; even if it is not exactly 256 bit long (represented by a `msg_addr_var`).
|
||||||
|
(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR";
|
||||||
|
|
||||||
|
{-
|
||||||
|
# Dictionary primitives
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
;;; Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell),
|
||||||
|
;;; and returns the resulting dictionary.
|
||||||
|
cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
|
||||||
|
(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF";
|
||||||
|
|
||||||
|
;;; Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell),
|
||||||
|
;;; and returns the resulting dictionary.
|
||||||
|
cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||||
|
(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF";
|
||||||
|
|
||||||
|
cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF";
|
||||||
|
(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF";
|
||||||
|
(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF";
|
||||||
|
(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL";
|
||||||
|
(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL";
|
||||||
|
(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT";
|
||||||
|
(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, cell, int) idict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, cell, int) udict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, (cell, int)) ~idict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, (cell, int)) ~udict_delete_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGETREF" "NULLSWAPIFNOT";
|
||||||
|
cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
|
||||||
|
(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET";
|
||||||
|
cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
|
||||||
|
(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET";
|
||||||
|
cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
|
||||||
|
(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET";
|
||||||
|
(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD";
|
||||||
|
(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE";
|
||||||
|
(cell, int) udict_replace_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUREPLACEREF";
|
||||||
|
(cell, slice, int) udict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACEGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, cell, int) udict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUREPLACEGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, (slice, int)) ~udict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACEGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, (cell, int)) ~udict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUREPLACEGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD";
|
||||||
|
(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE";
|
||||||
|
(cell, int) idict_replace_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTIREPLACEREF";
|
||||||
|
(cell, slice, int) idict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACEGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, cell, int) idict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTIREPLACEGETREF" "NULLSWAPIFNOT";
|
||||||
|
(cell, (slice, int)) ~idict_replaceget?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACEGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, (cell, int)) ~idict_replaceget_ref?(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTIREPLACEGETREF" "NULLSWAPIFNOT";
|
||||||
|
cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
|
||||||
|
(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB";
|
||||||
|
cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
|
||||||
|
(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB";
|
||||||
|
cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
|
||||||
|
(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB";
|
||||||
|
(cell, int) dict_replace_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTREPLACEB";
|
||||||
|
(cell, builder, int) dict_replaceget_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTREPLACEGETB" "NULLSWAPIFNOT";
|
||||||
|
(cell, slice, int) dict_replaceget?(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTREPLACEGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, (builder, int)) ~dict_replaceget_builder?(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTREPLACEGETB" "NULLSWAPIFNOT";
|
||||||
|
(cell, (slice, int)) ~dict_replaceget?(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTREPLACEGET" "NULLSWAPIFNOT";
|
||||||
|
(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB";
|
||||||
|
(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB";
|
||||||
|
(cell, builder, int) udict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEGETB" "NULLSWAPIFNOT";
|
||||||
|
(cell, (builder, int)) ~udict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEGETB" "NULLSWAPIFNOT";
|
||||||
|
(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB";
|
||||||
|
(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB";
|
||||||
|
(cell, builder, int) idict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEGETB" "NULLSWAPIFNOT";
|
||||||
|
(cell, (builder, int)) ~idict_replaceget_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEGETB" "NULLSWAPIFNOT";
|
||||||
|
(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
|
||||||
|
(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
|
||||||
|
(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";
|
||||||
|
(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";
|
||||||
|
(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";
|
||||||
|
(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
;;; Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL
|
||||||
|
cell new_dict() asm "NEWDICT";
|
||||||
|
;;; Checks whether a dictionary is empty. Equivalent to cell_null?.
|
||||||
|
int dict_empty?(cell c) asm "DICTEMPTY";
|
||||||
|
|
||||||
|
|
||||||
|
{- Prefix dictionary primitives -}
|
||||||
|
(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
||||||
|
(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET";
|
||||||
|
(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL";
|
||||||
|
|
||||||
|
;;; Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value.
|
||||||
|
cell config_param(int x) asm "CONFIGOPTPARAM";
|
||||||
|
;;; Checks whether c is a null. Note, that FunC also has polymorphic null? built-in.
|
||||||
|
int cell_null?(cell c) asm "ISNULL";
|
||||||
|
|
||||||
|
;;; Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15.
|
||||||
|
() raw_reserve(int amount, int mode) impure asm "RAWRESERVE";
|
||||||
|
;;; Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved.
|
||||||
|
() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX";
|
||||||
|
;;; Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); mode = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128.
|
||||||
|
() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG";
|
||||||
|
;;; Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract
|
||||||
|
() set_code(cell new_code) impure asm "SETCODE";
|
||||||
|
|
||||||
|
;;; Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x.
|
||||||
|
int random() impure asm "RANDU256";
|
||||||
|
;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed.
|
||||||
|
int rand(int range) impure asm "RAND";
|
||||||
|
;;; Returns the current random seed as an unsigned 256-bit Integer.
|
||||||
|
int get_seed() impure asm "RANDSEED";
|
||||||
|
;;; Sets the random seed to unsigned 256-bit seed.
|
||||||
|
() set_seed(int x) impure asm "SETRAND";
|
||||||
|
;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x.
|
||||||
|
() randomize(int x) impure asm "ADDRAND";
|
||||||
|
;;; Equivalent to randomize(cur_lt());.
|
||||||
|
() randomize_lt() impure asm "LTIME" "ADDRAND";
|
||||||
|
|
||||||
|
;;; Checks whether the data parts of two slices coinside
|
||||||
|
int equal_slices_bits(slice a, slice b) asm "SDEQ";
|
||||||
|
;;; Checks whether b is a null. Note, that FunC also has polymorphic null? built-in.
|
||||||
|
int builder_null?(builder b) asm "ISNULL";
|
||||||
|
;;; Concatenates two builders
|
||||||
|
builder store_builder(builder to, builder from) asm "STBR";
|
||||||
|
|
||||||
|
;; CUSTOM:
|
||||||
|
|
||||||
|
;; TVM UPGRADE 2023-07 https://docs.ton.org/learn/tvm-instructions/tvm-upgrade-2023-07
|
||||||
|
;; In mainnet since 20 Dec 2023 https://t.me/tonblockchain/226
|
||||||
|
|
||||||
|
;;; Retrieves code of smart-contract from c7
|
||||||
|
|
||||||
|
cell my_code() asm "MYCODE";
|
|
@ -1,7 +1,7 @@
|
||||||
// Standard library for Tolk (LGPL licence).
|
// Standard library for Tolk (LGPL licence).
|
||||||
// It contains common functions that are available out of the box, the user doesn't have to import anything.
|
// It contains common functions that are available out of the box, the user doesn't have to import anything.
|
||||||
// More specific functions are required to be imported explicitly, like "@stdlib/tvm-dicts".
|
// More specific functions are required to be imported explicitly, like "@stdlib/tvm-dicts".
|
||||||
tolk 0.6
|
tolk 0.7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tuple manipulation primitives.
|
Tuple manipulation primitives.
|
||||||
|
@ -17,17 +17,17 @@ fun createEmptyTuple(): tuple
|
||||||
/// Appends a value to tuple, resulting in `Tuple t' = (x1, ..., xn, value)`.
|
/// Appends a value to tuple, resulting in `Tuple t' = (x1, ..., xn, value)`.
|
||||||
/// If its size exceeds 255, throws a type check exception.
|
/// If its size exceeds 255, throws a type check exception.
|
||||||
@pure
|
@pure
|
||||||
fun tuplePush<X>(mutate self: tuple, value: X): void
|
fun tuplePush<T>(mutate self: tuple, value: T): void
|
||||||
asm "TPUSH";
|
asm "TPUSH";
|
||||||
|
|
||||||
/// Returns the first element of a non-empty tuple.
|
/// Returns the first element of a non-empty tuple.
|
||||||
@pure
|
@pure
|
||||||
fun tupleFirst<X>(t: tuple): X
|
fun tupleFirst<T>(t: tuple): T
|
||||||
asm "FIRST";
|
asm "FIRST";
|
||||||
|
|
||||||
/// Returns the [`index`]-th element of a tuple.
|
/// Returns the [`index`]-th element of a tuple.
|
||||||
@pure
|
@pure
|
||||||
fun tupleAt<X>(t: tuple, index: int): X
|
fun tupleAt<T>(t: tuple, index: int): T
|
||||||
builtin;
|
builtin;
|
||||||
|
|
||||||
/// Returns the size of a tuple (elements count in it).
|
/// Returns the size of a tuple (elements count in it).
|
||||||
|
@ -37,7 +37,7 @@ fun tupleSize(t: tuple): int
|
||||||
|
|
||||||
/// Returns the last element of a non-empty tuple.
|
/// Returns the last element of a non-empty tuple.
|
||||||
@pure
|
@pure
|
||||||
fun tupleLast(t: tuple): int
|
fun tupleLast<T>(t: tuple): T
|
||||||
asm "LAST";
|
asm "LAST";
|
||||||
|
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ fun stringHash(s: slice): int
|
||||||
/// That is, if [hash] is computed as the hash of some data, these data are hashed twice,
|
/// That is, if [hash] is computed as the hash of some data, these data are hashed twice,
|
||||||
/// the second hashing occurring inside `CHKSIGNS`.
|
/// the second hashing occurring inside `CHKSIGNS`.
|
||||||
@pure
|
@pure
|
||||||
fun isSignatureValid(hash: int, signature: slice, publicKey: int): int
|
fun isSignatureValid(hash: int, signature: slice, publicKey: int): bool
|
||||||
asm "CHKSIGNU";
|
asm "CHKSIGNU";
|
||||||
|
|
||||||
/// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `publicKey`,
|
/// Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `publicKey`,
|
||||||
|
@ -214,7 +214,7 @@ fun isSignatureValid(hash: int, signature: slice, publicKey: int): int
|
||||||
/// The verification of Ed25519 signatures is the standard one,
|
/// The verification of Ed25519 signatures is the standard one,
|
||||||
/// with sha256 used to reduce [data] to the 256-bit number that is actually signed.
|
/// with sha256 used to reduce [data] to the 256-bit number that is actually signed.
|
||||||
@pure
|
@pure
|
||||||
fun isSliceSignatureValid(data: slice, signature: slice, publicKey: int): int
|
fun isSliceSignatureValid(data: slice, signature: slice, publicKey: int): bool
|
||||||
asm "CHKSIGNS";
|
asm "CHKSIGNS";
|
||||||
|
|
||||||
/// Generates a new pseudo-random unsigned 256-bit integer x.
|
/// Generates a new pseudo-random unsigned 256-bit integer x.
|
||||||
|
@ -259,14 +259,14 @@ fun randomizeByLogicalTime(): void
|
||||||
/// otherwise the computation is aborted before visiting the `(maxCells + 1)`-st cell and
|
/// otherwise the computation is aborted before visiting the `(maxCells + 1)`-st cell and
|
||||||
/// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`.
|
/// a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`.
|
||||||
@pure
|
@pure
|
||||||
fun calculateCellSize(c: cell, maxCells: int): (int, int, int, int)
|
fun calculateCellSize(c: cell, maxCells: int): (int, int, int, bool)
|
||||||
asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||||
|
|
||||||
/// Similar to [calculateCellSize], but accepting a `slice` [s] instead of a `cell`.
|
/// Similar to [calculateCellSize], but accepting a `slice` [s] instead of a `cell`.
|
||||||
/// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself;
|
/// The returned value of `x` does not take into account the cell that contains the `slice` [s] itself;
|
||||||
/// however, the data bits and the cell references of [s] are accounted for in `y` and `z`.
|
/// however, the data bits and the cell references of [s] are accounted for in `y` and `z`.
|
||||||
@pure
|
@pure
|
||||||
fun calculateSliceSize(s: slice, maxCells: int): (int, int, int, int)
|
fun calculateSliceSize(s: slice, maxCells: int): (int, int, int, bool)
|
||||||
asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||||
|
|
||||||
/// A non-quiet version of [calculateCellSize] that throws a cell overflow exception (`8`) on failure.
|
/// A non-quiet version of [calculateCellSize] that throws a cell overflow exception (`8`) on failure.
|
||||||
|
@ -306,11 +306,11 @@ fun getBuilderDepth(b: builder): int
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Dump a variable [x] to the debug log.
|
/// Dump a variable [x] to the debug log.
|
||||||
fun debugPrint<X>(x: X): void
|
fun debugPrint<T>(x: T): void
|
||||||
builtin;
|
builtin;
|
||||||
|
|
||||||
/// Dump a string [x] to the debug log.
|
/// Dump a string [x] to the debug log.
|
||||||
fun debugPrintString<X>(x: X): void
|
fun debugPrintString<T>(x: T): void
|
||||||
builtin;
|
builtin;
|
||||||
|
|
||||||
/// Dumps the stack (at most the top 255 values) and shows the total stack depth.
|
/// Dumps the stack (at most the top 255 values) and shows the total stack depth.
|
||||||
|
@ -382,7 +382,7 @@ fun loadCoins(mutate self: slice): int
|
||||||
|
|
||||||
/// Loads bool (-1 or 0) from a slice
|
/// Loads bool (-1 or 0) from a slice
|
||||||
@pure
|
@pure
|
||||||
fun loadBool(mutate self: slice): int
|
fun loadBool(mutate self: slice): bool
|
||||||
asm( -> 1 0) "1 LDI";
|
asm( -> 1 0) "1 LDI";
|
||||||
|
|
||||||
/// Shifts a slice pointer to [len] bits forward, mutating the slice.
|
/// Shifts a slice pointer to [len] bits forward, mutating the slice.
|
||||||
|
@ -482,7 +482,7 @@ fun storeCoins(mutate self: builder, x: int): self
|
||||||
/// Stores bool (-1 or 0) into a builder.
|
/// Stores bool (-1 or 0) into a builder.
|
||||||
/// Attention: true value is `-1`, not 1! If you pass `1` here, TVM will throw an exception.
|
/// Attention: true value is `-1`, not 1! If you pass `1` here, TVM will throw an exception.
|
||||||
@pure
|
@pure
|
||||||
fun storeBool(mutate self: builder, x: int): self
|
fun storeBool(mutate self: builder, x: bool): self
|
||||||
asm(x self) "1 STI";
|
asm(x self) "1 STI";
|
||||||
|
|
||||||
/// Stores dictionary (represented by TVM `cell` or `null`) into a builder.
|
/// Stores dictionary (represented by TVM `cell` or `null`) into a builder.
|
||||||
|
@ -529,22 +529,22 @@ fun getRemainingBitsAndRefsCount(self: slice): (int, int)
|
||||||
|
|
||||||
/// Checks whether a slice is empty (i.e., contains no bits of data and no cell references).
|
/// Checks whether a slice is empty (i.e., contains no bits of data and no cell references).
|
||||||
@pure
|
@pure
|
||||||
fun isEndOfSlice(self: slice): int
|
fun isEndOfSlice(self: slice): bool
|
||||||
asm "SEMPTY";
|
asm "SEMPTY";
|
||||||
|
|
||||||
/// Checks whether a slice has no bits of data.
|
/// Checks whether a slice has no bits of data.
|
||||||
@pure
|
@pure
|
||||||
fun isEndOfSliceBits(self: slice): int
|
fun isEndOfSliceBits(self: slice): bool
|
||||||
asm "SDEMPTY";
|
asm "SDEMPTY";
|
||||||
|
|
||||||
/// Checks whether a slice has no references.
|
/// Checks whether a slice has no references.
|
||||||
@pure
|
@pure
|
||||||
fun isEndOfSliceRefs(self: slice): int
|
fun isEndOfSliceRefs(self: slice): bool
|
||||||
asm "SREMPTY";
|
asm "SREMPTY";
|
||||||
|
|
||||||
/// Checks whether data parts of two slices coinside.
|
/// Checks whether data parts of two slices coinside.
|
||||||
@pure
|
@pure
|
||||||
fun isSliceBitsEqual(self: slice, b: slice): int
|
fun isSliceBitsEqual(self: slice, b: slice): bool
|
||||||
asm "SDEQ";
|
asm "SDEQ";
|
||||||
|
|
||||||
/// Returns the number of cell references already stored in a builder.
|
/// Returns the number of cell references already stored in a builder.
|
||||||
|
@ -621,10 +621,10 @@ fun parseStandardAddress(s: slice): (int, int)
|
||||||
fun createAddressNone(): slice
|
fun createAddressNone(): slice
|
||||||
asm "b{00} PUSHSLICE";
|
asm "b{00} PUSHSLICE";
|
||||||
|
|
||||||
/// Returns if a slice pointer contains an empty address (`-1` for true, `0` for false, as always).
|
/// Returns if a slice pointer contains an empty address.
|
||||||
/// In other words, a slice starts with two `0` bits (TL addr_none$00).
|
/// In other words, a slice starts with two `0` bits (TL addr_none$00).
|
||||||
@pure
|
@pure
|
||||||
fun addressIsNone(s: slice): int
|
fun addressIsNone(s: slice): bool
|
||||||
asm "2 PLDU" "0 EQINT";
|
asm "2 PLDU" "0 EQINT";
|
||||||
|
|
||||||
|
|
||||||
|
@ -677,8 +677,8 @@ fun loadMessageFlags(mutate self: slice): int
|
||||||
/// Having msgFlags (4 bits), check that a message is bounced.
|
/// Having msgFlags (4 bits), check that a message is bounced.
|
||||||
/// Effectively, it's `msgFlags & 1` (the lowest bit present).
|
/// Effectively, it's `msgFlags & 1` (the lowest bit present).
|
||||||
@pure
|
@pure
|
||||||
fun isMessageBounced(msgFlags: int): int
|
fun isMessageBounced(msgFlags: int): bool
|
||||||
asm "1 PUSHINT" "AND";
|
asm "2 PUSHINT" "MODR";
|
||||||
|
|
||||||
/// Skip 0xFFFFFFFF prefix (when a message is bounced).
|
/// Skip 0xFFFFFFFF prefix (when a message is bounced).
|
||||||
@pure
|
@pure
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// A part of standard library for Tolk
|
// A part of standard library for Tolk
|
||||||
tolk 0.6
|
tolk 0.7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Gas and payment related primitives.
|
Gas and payment related primitives.
|
||||||
|
@ -61,3 +61,9 @@ fun calculateOriginalMessageFee(workchain: int, incomingFwdFee: int): int
|
||||||
/// If it has no debt, `0` is returned.
|
/// If it has no debt, `0` is returned.
|
||||||
fun getMyStorageDuePayment(): int
|
fun getMyStorageDuePayment(): int
|
||||||
asm "DUEPAYMENT";
|
asm "DUEPAYMENT";
|
||||||
|
|
||||||
|
/// Returns the amount of nanotoncoins charged for storage.
|
||||||
|
/// (during storage phase preceeding to current computation phase)
|
||||||
|
@pure
|
||||||
|
fun getMyStoragePaidPayment(): int
|
||||||
|
asm "STORAGEFEES";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// A part of standard library for Tolk
|
// A part of standard library for Tolk
|
||||||
tolk 0.6
|
tolk 0.7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Lisp-style lists are nested 2-elements tuples: `(1, (2, (3, null)))` represents list `[1, 2, 3]`.
|
Lisp-style lists are nested 2-elements tuples: `(1, (2, (3, null)))` represents list `[1, 2, 3]`.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// A part of standard library for Tolk
|
// A part of standard library for Tolk
|
||||||
tolk 0.6
|
tolk 0.7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Dictionaries are represented as `cell` data type (cells can store anything, dicts in particular).
|
Dictionaries are represented as `cell` data type (cells can store anything, dicts in particular).
|
||||||
|
@ -19,20 +19,20 @@ fun createEmptyDict(): cell
|
||||||
|
|
||||||
/// Checks whether a dictionary is empty.
|
/// Checks whether a dictionary is empty.
|
||||||
@pure
|
@pure
|
||||||
fun dictIsEmpty(self: cell): int
|
fun dictIsEmpty(self: cell): bool
|
||||||
asm "DICTEMPTY";
|
asm "DICTEMPTY";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGet(self: cell, keyLen: int, key: int): (slice, int)
|
fun iDictGet(self: cell, keyLen: int, key: int): (slice, bool)
|
||||||
asm(key self keyLen) "DICTIGET" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTIGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGet(self: cell, keyLen: int, key: int): (slice, int)
|
fun uDictGet(self: cell, keyLen: int, key: int): (slice, bool)
|
||||||
asm(key self keyLen) "DICTUGET" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTUGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictGet(self: cell, keyLen: int, key: slice): (slice, int)
|
fun sDictGet(self: cell, keyLen: int, key: slice): (slice, bool)
|
||||||
asm(key self keyLen) "DICTGET" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,33 +63,33 @@ fun sDictSetRef(mutate self: cell, keyLen: int, key: slice, value: cell): void
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictSetIfNotExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
fun iDictSetIfNotExists(mutate self: cell, keyLen: int, key: int, value: slice): bool
|
||||||
asm(value key self keyLen) "DICTIADD";
|
asm(value key self keyLen) "DICTIADD";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictSetIfNotExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
fun uDictSetIfNotExists(mutate self: cell, keyLen: int, key: int, value: slice): bool
|
||||||
asm(value key self keyLen) "DICTUADD";
|
asm(value key self keyLen) "DICTUADD";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictSetIfExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
fun iDictSetIfExists(mutate self: cell, keyLen: int, key: int, value: slice): bool
|
||||||
asm(value key self keyLen) "DICTIREPLACE";
|
asm(value key self keyLen) "DICTIREPLACE";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictSetIfExists(mutate self: cell, keyLen: int, key: int, value: slice): int
|
fun uDictSetIfExists(mutate self: cell, keyLen: int, key: int, value: slice): bool
|
||||||
asm(value key self keyLen) "DICTUREPLACE";
|
asm(value key self keyLen) "DICTUREPLACE";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetRef(self: cell, keyLen: int, key: int): (cell, int)
|
fun iDictGetRef(self: cell, keyLen: int, key: int): (cell, bool)
|
||||||
asm(key self keyLen) "DICTIGETREF" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTIGETREF" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetRef(self: cell, keyLen: int, key: int): (cell, int)
|
fun uDictGetRef(self: cell, keyLen: int, key: int): (cell, bool)
|
||||||
asm(key self keyLen) "DICTUGETREF" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTUGETREF" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictGetRef(self: cell, keyLen: int, key: slice): (cell, int)
|
fun sDictGetRef(self: cell, keyLen: int, key: slice): (cell, bool)
|
||||||
asm(key self keyLen) "DICTGETREF" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTGETREF" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
|
|
||||||
|
@ -107,28 +107,28 @@ fun sDictGetRefOrNull(self: cell, keyLen: int, key: slice): cell
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictDelete(mutate self: cell, keyLen: int, key: int): int
|
fun iDictDelete(mutate self: cell, keyLen: int, key: int): bool
|
||||||
asm(key self keyLen) "DICTIDEL";
|
asm(key self keyLen) "DICTIDEL";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictDelete(mutate self: cell, keyLen: int, key: int): int
|
fun uDictDelete(mutate self: cell, keyLen: int, key: int): bool
|
||||||
asm(key self keyLen) "DICTUDEL";
|
asm(key self keyLen) "DICTUDEL";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictDelete(mutate self: cell, keyLen: int, key: slice): int
|
fun sDictDelete(mutate self: cell, keyLen: int, key: slice): bool
|
||||||
asm(key self keyLen) "DICTDEL";
|
asm(key self keyLen) "DICTDEL";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictSetAndGet(mutate self: cell, keyLen: int, key: int, value: slice): (slice, int)
|
fun iDictSetAndGet(mutate self: cell, keyLen: int, key: int, value: slice): (slice, bool)
|
||||||
asm(value key self keyLen) "DICTISETGET" "NULLSWAPIFNOT";
|
asm(value key self keyLen) "DICTISETGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictSetAndGet(mutate self: cell, keyLen: int, key: int, value: slice): (slice, int)
|
fun uDictSetAndGet(mutate self: cell, keyLen: int, key: int, value: slice): (slice, bool)
|
||||||
asm(value key self keyLen) "DICTUSETGET" "NULLSWAPIFNOT";
|
asm(value key self keyLen) "DICTUSETGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictSetAndGet(mutate self: cell, keyLen: int, key: slice, value: slice): (slice, int)
|
fun sDictSetAndGet(mutate self: cell, keyLen: int, key: slice, value: slice): (slice, bool)
|
||||||
asm(value key self keyLen) "DICTSETGET" "NULLSWAPIFNOT";
|
asm(value key self keyLen) "DICTSETGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,15 +142,15 @@ fun uDictSetAndGetRefOrNull(mutate self: cell, keyLen: int, key: int, value: cel
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictDeleteAndGet(mutate self: cell, keyLen: int, key: int): (slice, int)
|
fun iDictDeleteAndGet(mutate self: cell, keyLen: int, key: int): (slice, bool)
|
||||||
asm(key self keyLen) "DICTIDELGET" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTIDELGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictDeleteAndGet(mutate self: cell, keyLen: int, key: int): (slice, int)
|
fun uDictDeleteAndGet(mutate self: cell, keyLen: int, key: int): (slice, bool)
|
||||||
asm(key self keyLen) "DICTUDELGET" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTUDELGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictDeleteAndGet(mutate self: cell, keyLen: int, key: slice): (slice, int)
|
fun sDictDeleteAndGet(mutate self: cell, keyLen: int, key: slice): (slice, bool)
|
||||||
asm(key self keyLen) "DICTDELGET" "NULLSWAPIFNOT";
|
asm(key self keyLen) "DICTDELGET" "NULLSWAPIFNOT";
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,129 +168,129 @@ fun sDictSetBuilder(mutate self: cell, keyLen: int, key: slice, value: builder):
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictSetBuilderIfNotExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
fun iDictSetBuilderIfNotExists(mutate self: cell, keyLen: int, key: int, value: builder): bool
|
||||||
asm(value key self keyLen) "DICTIADDB";
|
asm(value key self keyLen) "DICTIADDB";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictSetBuilderIfNotExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
fun uDictSetBuilderIfNotExists(mutate self: cell, keyLen: int, key: int, value: builder): bool
|
||||||
asm(value key self keyLen) "DICTUADDB";
|
asm(value key self keyLen) "DICTUADDB";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictSetBuilderIfExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
fun iDictSetBuilderIfExists(mutate self: cell, keyLen: int, key: int, value: builder): bool
|
||||||
asm(value key self keyLen) "DICTIREPLACEB";
|
asm(value key self keyLen) "DICTIREPLACEB";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictSetBuilderIfExists(mutate self: cell, keyLen: int, key: int, value: builder): int
|
fun uDictSetBuilderIfExists(mutate self: cell, keyLen: int, key: int, value: builder): bool
|
||||||
asm(value key self keyLen) "DICTUREPLACEB";
|
asm(value key self keyLen) "DICTUREPLACEB";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
fun iDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
fun uDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (slice, slice, int)
|
fun sDictDeleteFirstAndGet(mutate self: cell, keyLen: int): (slice, slice, bool)
|
||||||
asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictDeleteLastAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
fun iDictDeleteLastAndGet(mutate self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictDeleteLastAndGet(mutate self: cell, keyLen: int): (int, slice, int)
|
fun uDictDeleteLastAndGet(mutate self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictDeleteLastAndGet(mutate self: cell, keyLen: int): (slice, slice, int)
|
fun sDictDeleteLastAndGet(mutate self: cell, keyLen: int): (slice, slice, bool)
|
||||||
asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetFirst(self: cell, keyLen: int): (int, slice, int)
|
fun iDictGetFirst(self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetFirst(self: cell, keyLen: int): (int, slice, int)
|
fun uDictGetFirst(self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictGetFirst(self: cell, keyLen: int): (slice, slice, int)
|
fun sDictGetFirst(self: cell, keyLen: int): (slice, slice, bool)
|
||||||
asm (-> 1 0 2) "DICTMIN" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTMIN" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetFirstAsRef(self: cell, keyLen: int): (int, cell, int)
|
fun iDictGetFirstAsRef(self: cell, keyLen: int): (int, cell, bool)
|
||||||
asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetFirstAsRef(self: cell, keyLen: int): (int, cell, int)
|
fun uDictGetFirstAsRef(self: cell, keyLen: int): (int, cell, bool)
|
||||||
asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictGetFirstAsRef(self: cell, keyLen: int): (slice, cell, int)
|
fun sDictGetFirstAsRef(self: cell, keyLen: int): (slice, cell, bool)
|
||||||
asm (-> 1 0 2) "DICTMINREF" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTMINREF" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetLast(self: cell, keyLen: int): (int, slice, int)
|
fun iDictGetLast(self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetLast(self: cell, keyLen: int): (int, slice, int)
|
fun uDictGetLast(self: cell, keyLen: int): (int, slice, bool)
|
||||||
asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictGetLast(self: cell, keyLen: int): (slice, slice, int)
|
fun sDictGetLast(self: cell, keyLen: int): (slice, slice, bool)
|
||||||
asm (-> 1 0 2) "DICTMAX" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTMAX" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetLastAsRef(self: cell, keyLen: int): (int, cell, int)
|
fun iDictGetLastAsRef(self: cell, keyLen: int): (int, cell, bool)
|
||||||
asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetLastAsRef(self: cell, keyLen: int): (int, cell, int)
|
fun uDictGetLastAsRef(self: cell, keyLen: int): (int, cell, bool)
|
||||||
asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun sDictGetLastAsRef(self: cell, keyLen: int): (slice, cell, int)
|
fun sDictGetLastAsRef(self: cell, keyLen: int): (slice, cell, bool)
|
||||||
asm (-> 1 0 2) "DICTMAXREF" "NULLSWAPIFNOT2";
|
asm (-> 1 0 2) "DICTMAXREF" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetNext(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun iDictGetNext(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetNext(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun uDictGetNext(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetNextOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun iDictGetNextOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetNextOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun uDictGetNextOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetPrev(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun iDictGetPrev(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetPrev(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun uDictGetPrev(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun iDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun iDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun uDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
fun uDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, bool)
|
||||||
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
|
asm(pivot self keyLen -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
|
|
||||||
|
@ -299,13 +299,13 @@ fun uDictGetPrevOrEqual(self: cell, keyLen: int, pivot: int): (int, slice, int)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun prefixDictGet(self: cell, keyLen: int, key: slice): (slice, slice, slice, int)
|
fun prefixDictGet(self: cell, keyLen: int, key: slice): (slice, slice, slice, bool)
|
||||||
asm(key self keyLen) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
asm(key self keyLen) "PFXDICTGETQ" "NULLSWAPIFNOT2";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun prefixDictSet(mutate self: cell, keyLen: int, key: slice, value: slice): int
|
fun prefixDictSet(mutate self: cell, keyLen: int, key: slice, value: slice): bool
|
||||||
asm(value key self keyLen) "PFXDICTSET";
|
asm(value key self keyLen) "PFXDICTSET";
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun prefixDictDelete(mutate self: cell, keyLen: int, key: slice): int
|
fun prefixDictDelete(mutate self: cell, keyLen: int, key: slice): bool
|
||||||
asm(key self keyLen) "PFXDICTDEL";
|
asm(key self keyLen) "PFXDICTDEL";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// A part of standard library for Tolk
|
// A part of standard library for Tolk
|
||||||
tolk 0.6
|
tolk 0.7
|
||||||
|
|
||||||
/// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.
|
/// Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.
|
||||||
/// The primitive returns the current value of `c3`.
|
/// The primitive returns the current value of `c3`.
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct GetMethodParams {
|
||||||
std::string address;
|
std::string address;
|
||||||
uint32_t unixtime;
|
uint32_t unixtime;
|
||||||
uint64_t balance;
|
uint64_t balance;
|
||||||
|
std::string extra_currencies;
|
||||||
std::string rand_seed_hex;
|
std::string rand_seed_hex;
|
||||||
int64_t gas_limit;
|
int64_t gas_limit;
|
||||||
int method_id;
|
int method_id;
|
||||||
|
@ -108,6 +109,32 @@ td::Result<GetMethodParams> decode_get_method_params(const char* json) {
|
||||||
TRY_RESULT(balance, td::to_integer_safe<td::uint64>(balance_field.get_string()));
|
TRY_RESULT(balance, td::to_integer_safe<td::uint64>(balance_field.get_string()));
|
||||||
params.balance = balance;
|
params.balance = balance;
|
||||||
|
|
||||||
|
TRY_RESULT(ec_field, td::get_json_object_field(obj, "extra_currencies", td::JsonValue::Type::Object, true));
|
||||||
|
if (ec_field.type() != td::JsonValue::Type::Null) {
|
||||||
|
if (ec_field.type() != td::JsonValue::Type::Object) {
|
||||||
|
return td::Status::Error("EC must be of type Object");
|
||||||
|
}
|
||||||
|
td::StringBuilder ec_builder;
|
||||||
|
auto& ec_obj = ec_field.get_object();
|
||||||
|
bool is_first = true;
|
||||||
|
for (auto &field_value : ec_obj) {
|
||||||
|
auto currency_id = field_value.first;
|
||||||
|
if (field_value.second.type() != td::JsonValue::Type::String) {
|
||||||
|
return td::Status::Error(PSLICE() << "EC amount must be of type String");
|
||||||
|
}
|
||||||
|
auto amount = field_value.second.get_string();
|
||||||
|
if (!is_first) {
|
||||||
|
ec_builder << " ";
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
ec_builder << currency_id << "=" << amount;
|
||||||
|
}
|
||||||
|
if (ec_builder.is_error()) {
|
||||||
|
return td::Status::Error(PSLICE() << "Error building extra currencies string");
|
||||||
|
}
|
||||||
|
params.extra_currencies = ec_builder.as_cslice().str();
|
||||||
|
}
|
||||||
|
|
||||||
TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", false));
|
TRY_RESULT(rand_seed_str, td::get_json_object_string_field(obj, "rand_seed", false));
|
||||||
params.rand_seed_hex = rand_seed_str;
|
params.rand_seed_hex = rand_seed_str;
|
||||||
|
|
||||||
|
@ -228,8 +255,8 @@ const char *run_get_method(const char *params, const char* stack, const char* co
|
||||||
if ((decoded_params.libs && !tvm_emulator_set_libraries(tvm, decoded_params.libs.value().c_str())) ||
|
if ((decoded_params.libs && !tvm_emulator_set_libraries(tvm, decoded_params.libs.value().c_str())) ||
|
||||||
!tvm_emulator_set_c7(tvm, decoded_params.address.c_str(), decoded_params.unixtime, decoded_params.balance,
|
!tvm_emulator_set_c7(tvm, decoded_params.address.c_str(), decoded_params.unixtime, decoded_params.balance,
|
||||||
decoded_params.rand_seed_hex.c_str(), config) ||
|
decoded_params.rand_seed_hex.c_str(), config) ||
|
||||||
(decoded_params.prev_blocks_info &&
|
(decoded_params.extra_currencies.size() > 0 && !tvm_emulator_set_extra_currencies(tvm, decoded_params.extra_currencies.c_str())) ||
|
||||||
!tvm_emulator_set_prev_blocks_info(tvm, decoded_params.prev_blocks_info.value().c_str())) ||
|
(decoded_params.prev_blocks_info && !tvm_emulator_set_prev_blocks_info(tvm, decoded_params.prev_blocks_info.value().c_str())) ||
|
||||||
(decoded_params.gas_limit > 0 && !tvm_emulator_set_gas_limit(tvm, decoded_params.gas_limit)) ||
|
(decoded_params.gas_limit > 0 && !tvm_emulator_set_gas_limit(tvm, decoded_params.gas_limit)) ||
|
||||||
!tvm_emulator_set_debug_enabled(tvm, decoded_params.debug_enabled)) {
|
!tvm_emulator_set_debug_enabled(tvm, decoded_params.debug_enabled)) {
|
||||||
tvm_emulator_destroy(tvm);
|
tvm_emulator_destroy(tvm);
|
||||||
|
|
|
@ -496,6 +496,59 @@ bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool tvm_emulator_set_extra_currencies(void *tvm_emulator, const char *extra_currencies) {
|
||||||
|
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
||||||
|
vm::Dictionary dict{32};
|
||||||
|
td::Slice extra_currencies_str{extra_currencies};
|
||||||
|
while (true) {
|
||||||
|
auto next_space_pos = extra_currencies_str.find(' ');
|
||||||
|
auto currency_id_amount = next_space_pos == td::Slice::npos ?
|
||||||
|
extra_currencies_str.substr(0) : extra_currencies_str.substr(0, next_space_pos);
|
||||||
|
|
||||||
|
if (!currency_id_amount.empty()) {
|
||||||
|
auto delim_pos = currency_id_amount.find('=');
|
||||||
|
if (delim_pos == td::Slice::npos) {
|
||||||
|
LOG(ERROR) << "Invalid extra currency format, missing '='";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto currency_id_str = currency_id_amount.substr(0, delim_pos);
|
||||||
|
auto amount_str = currency_id_amount.substr(delim_pos + 1);
|
||||||
|
|
||||||
|
auto currency_id = td::to_integer_safe<uint32_t>(currency_id_str);
|
||||||
|
if (currency_id.is_error()) {
|
||||||
|
LOG(ERROR) << "Invalid extra currency id: " << currency_id_str;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto amount = td::dec_string_to_int256(amount_str);
|
||||||
|
if (amount.is_null()) {
|
||||||
|
LOG(ERROR) << "Invalid extra currency amount: " << amount_str;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (amount == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (amount < 0) {
|
||||||
|
LOG(ERROR) << "Negative extra currency amount: " << amount_str;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm::CellBuilder cb;
|
||||||
|
block::tlb::t_VarUInteger_32.store_integer_value(cb, *amount);
|
||||||
|
if (!dict.set_builder(td::BitArray<32>(currency_id.ok()), cb, vm::DictionaryBase::SetMode::Add)) {
|
||||||
|
LOG(ERROR) << "Duplicate extra currency id";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (next_space_pos == td::Slice::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extra_currencies_str.remove_prefix(next_space_pos + 1);
|
||||||
|
}
|
||||||
|
emulator->set_extra_currencies(std::move(dict).extract_root_cell());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool tvm_emulator_set_config_object(void* tvm_emulator, void* config) {
|
bool tvm_emulator_set_config_object(void* tvm_emulator, void* config) {
|
||||||
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
auto emulator = static_cast<emulator::TvmEmulator *>(tvm_emulator);
|
||||||
auto global_config = std::shared_ptr<block::Config>(static_cast<block::Config *>(config), config_deleter);
|
auto global_config = std::shared_ptr<block::Config>(static_cast<block::Config *>(config), config_deleter);
|
||||||
|
|
|
@ -182,6 +182,14 @@ EMULATOR_EXPORT bool tvm_emulator_set_libraries(void *tvm_emulator, const char *
|
||||||
*/
|
*/
|
||||||
EMULATOR_EXPORT bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config);
|
EMULATOR_EXPORT bool tvm_emulator_set_c7(void *tvm_emulator, const char *address, uint32_t unixtime, uint64_t balance, const char *rand_seed_hex, const char *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set extra currencies balance
|
||||||
|
* @param tvm_emulator Pointer to TVM emulator
|
||||||
|
* @param extra_currencies String with extra currencies balance in format "currency_id1=balance1 currency_id2=balance2 ..."
|
||||||
|
* @return true in case of success, false in case of error
|
||||||
|
*/
|
||||||
|
EMULATOR_EXPORT bool tvm_emulator_set_extra_currencies(void *tvm_emulator, const char *extra_currencies);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set config for TVM emulator
|
* @brief Set config for TVM emulator
|
||||||
* @param tvm_emulator Pointer to TVM emulator
|
* @param tvm_emulator Pointer to TVM emulator
|
||||||
|
|
|
@ -17,6 +17,7 @@ _emulator_config_destroy
|
||||||
_tvm_emulator_create
|
_tvm_emulator_create
|
||||||
_tvm_emulator_set_libraries
|
_tvm_emulator_set_libraries
|
||||||
_tvm_emulator_set_c7
|
_tvm_emulator_set_c7
|
||||||
|
_tvm_emulator_set_extra_currencies
|
||||||
_tvm_emulator_set_config_object
|
_tvm_emulator_set_config_object
|
||||||
_tvm_emulator_set_prev_blocks_info
|
_tvm_emulator_set_prev_blocks_info
|
||||||
_tvm_emulator_set_gas_limit
|
_tvm_emulator_set_gas_limit
|
||||||
|
|
|
@ -400,3 +400,58 @@ TEST(Emulator, tvm_emulator) {
|
||||||
CHECK(stack_res->depth() == 1);
|
CHECK(stack_res->depth() == 1);
|
||||||
CHECK(stack_res.write().pop_int()->to_long() == init_data.seqno);
|
CHECK(stack_res.write().pop_int()->to_long() == init_data.seqno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Emulator, tvm_emulator_extra_currencies) {
|
||||||
|
void *tvm_emulator = tvm_emulator_create("te6cckEBBAEAHgABFP8A9KQT9LzyyAsBAgFiAgMABtBfBAAJofpP8E8XmGlj", "te6cckEBAQEAAgAAAEysuc0=", 1);
|
||||||
|
std::string addr = "0:" + std::string(64, 'F');
|
||||||
|
tvm_emulator_set_c7(tvm_emulator, addr.c_str(), 1337, 1000, std::string(64, 'F').c_str(), nullptr);
|
||||||
|
CHECK(tvm_emulator_set_extra_currencies(tvm_emulator, "100=20000 200=1"));
|
||||||
|
unsigned method_crc = td::crc16("get_balance");
|
||||||
|
unsigned method_id = (method_crc & 0xffff) | 0x10000;
|
||||||
|
|
||||||
|
auto stack = td::make_ref<vm::Stack>();
|
||||||
|
vm::CellBuilder stack_cb;
|
||||||
|
CHECK(stack->serialize(stack_cb));
|
||||||
|
auto stack_cell = stack_cb.finalize();
|
||||||
|
auto stack_boc = td::base64_encode(std_boc_serialize(stack_cell).move_as_ok());
|
||||||
|
|
||||||
|
std::string tvm_res = tvm_emulator_run_get_method(tvm_emulator, method_id, stack_boc.c_str());
|
||||||
|
|
||||||
|
auto result_json = td::json_decode(td::MutableSlice(tvm_res));
|
||||||
|
auto result = result_json.move_as_ok();
|
||||||
|
auto& result_obj = result.get_object();
|
||||||
|
|
||||||
|
auto success_field = td::get_json_object_field(result_obj, "success", td::JsonValue::Type::Boolean, false);
|
||||||
|
auto success = success_field.move_as_ok().get_boolean();
|
||||||
|
CHECK(success);
|
||||||
|
|
||||||
|
auto stack_field = td::get_json_object_field(result_obj, "stack", td::JsonValue::Type::String, false);
|
||||||
|
auto stack_val = stack_field.move_as_ok();
|
||||||
|
auto& stack_obj = stack_val.get_string();
|
||||||
|
auto stack_res_boc = td::base64_decode(stack_obj);
|
||||||
|
auto stack_res_cell = vm::std_boc_deserialize(stack_res_boc.move_as_ok());
|
||||||
|
td::Ref<vm::Stack> stack_res;
|
||||||
|
auto stack_res_cs = vm::load_cell_slice(stack_res_cell.move_as_ok());
|
||||||
|
CHECK(vm::Stack::deserialize_to(stack_res_cs, stack_res));
|
||||||
|
CHECK(stack_res->depth() == 1);
|
||||||
|
auto tuple = stack_res.write().pop_tuple();
|
||||||
|
CHECK(tuple->size() == 2);
|
||||||
|
|
||||||
|
auto ton_balance = tuple->at(0).as_int();
|
||||||
|
CHECK(ton_balance == 1000);
|
||||||
|
|
||||||
|
auto cell = tuple->at(1).as_cell();
|
||||||
|
auto dict = vm::Dictionary{cell, 32};
|
||||||
|
auto it = dict.begin();
|
||||||
|
std::map<uint32_t, td::RefInt256> ec_balance;
|
||||||
|
while (!it.eof()) {
|
||||||
|
auto id = static_cast<uint32_t>(td::BitArray<32>(it.cur_pos()).to_ulong());
|
||||||
|
auto value_cs = it.cur_value();
|
||||||
|
auto value = block::tlb::t_VarUInteger_32.as_integer(value_cs);
|
||||||
|
ec_balance[id] = value;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
CHECK(ec_balance.size() == 2);
|
||||||
|
CHECK(ec_balance[100] == 20000);
|
||||||
|
CHECK(ec_balance[200] == 1);
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_extra_currencies(td::Ref<vm::Cell> extra_currencies) {
|
||||||
|
args_.set_extra_currencies(std::move(extra_currencies));
|
||||||
|
}
|
||||||
|
|
||||||
void set_c7_raw(td::Ref<vm::Tuple> c7) {
|
void set_c7_raw(td::Ref<vm::Tuple> c7) {
|
||||||
args_.set_c7(std::move(c7));
|
args_.set_c7(std::move(c7));
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ fun test88(x: int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(89)
|
@method_id(89)
|
||||||
fun test89(last: int) {
|
fun test89(last: int): (int, int, int, int) {
|
||||||
var t: tuple = createEmptyTuple();
|
var t: tuple = createEmptyTuple();
|
||||||
t.tuplePush(1);
|
t.tuplePush(1);
|
||||||
t.tuplePush(2);
|
t.tuplePush(2);
|
||||||
|
|
|
@ -9,6 +9,7 @@ fun calc_phi(): int {
|
||||||
repeat (70) { n*=10; };
|
repeat (70) { n*=10; };
|
||||||
var p= 1;
|
var p= 1;
|
||||||
var `q`=1;
|
var `q`=1;
|
||||||
|
_=`q`;
|
||||||
do {
|
do {
|
||||||
(p,q)=(q,p+q);
|
(p,q)=(q,p+q);
|
||||||
} while (q <= n); //;;
|
} while (q <= n); //;;
|
||||||
|
@ -27,7 +28,7 @@ fun calc_sqrt2(): int {
|
||||||
return mulDivRound(p, n, q);
|
return mulDivRound(p, n, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calc_root(m: auto): auto {
|
fun calc_root(m: int) {
|
||||||
var base: int=1;
|
var base: int=1;
|
||||||
repeat(70) { base *= 10; }
|
repeat(70) { base *= 10; }
|
||||||
var (a, b, c) = (1,0,-m);
|
var (a, b, c) = (1,0,-m);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@deprecated
|
@deprecated
|
||||||
fun twice(f: auto, x: auto): auto {
|
fun twice(f: int -> int, x: int) {
|
||||||
return f (f (x));
|
return f (f (x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,85 +2,112 @@ fun unsafe_tuple<X>(x: X): tuple
|
||||||
asm "NOP";
|
asm "NOP";
|
||||||
|
|
||||||
fun inc(x: int, y: int): (int, int) {
|
fun inc(x: int, y: int): (int, int) {
|
||||||
return (x + y, y * 10);
|
return (x + y, y * 10);
|
||||||
}
|
}
|
||||||
fun `~inc`(mutate self: int, y: int): int {
|
fun `~inc`(mutate self: int, y: int): int {
|
||||||
val (newX, newY) = inc(self, y);
|
val (newX, newY) = inc(self, y);
|
||||||
self = newX;
|
self = newX;
|
||||||
return newY;
|
return newY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun eq<X>(v: X): X { return v; }
|
||||||
|
fun eq2(v: (int, int)) { return v; }
|
||||||
|
fun mul2(mutate dest: int, v: int): int { dest = v*2; return dest; }
|
||||||
|
fun multens(mutate self: (int, int), v: (int, int)): (int, int) { var (f, s) = self; var (m1, m2) = v; self = (f*m1, s*m2); return self; }
|
||||||
|
|
||||||
@method_id(11)
|
@method_id(11)
|
||||||
fun test_return(x: int): (int, int, int, int, int, int, int) {
|
fun test_return(x: int): (int, int, int, int, int, int, int) {
|
||||||
return (x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
return (x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(12)
|
@method_id(12)
|
||||||
fun test_assign(x: int): (int, int, int, int, int, int, int) {
|
fun test_assign(x: int): (int, int, int, int, int, int, int) {
|
||||||
var (x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int) = (x, x.`~inc`(x / 20), x, x=x*2, x, x+=1, x);
|
var (x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int) = (x, x.`~inc`(x / 20), x, x=x*2, x, x+=1, x);
|
||||||
return (x1, x2, x3, x4, x5, x6, x7);
|
return (x1, x2, x3, x4, x5, x6, x7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(13)
|
@method_id(13)
|
||||||
fun test_tuple(x: int): tuple {
|
fun test_tuple(x: int): tuple {
|
||||||
var t: tuple = unsafe_tuple([x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x]);
|
var t: tuple = unsafe_tuple([x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x]);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(14)
|
@method_id(14)
|
||||||
fun test_tuple_assign(x: int): (int, int, int, int, int, int, int) {
|
fun test_tuple_assign(x: int): (int, int, int, int, int, int, int) {
|
||||||
var [x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int] = [x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x];
|
var [x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int] = [x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x];
|
||||||
return (x1, x2, x3, x4, x5, x6, x7);
|
return (x1, x2, x3, x4, x5, x6, x7);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo1(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int) {
|
fun foo1(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int) {
|
||||||
return (x1, x2, x3, x4, x5, x6, x7);
|
return (x1, x2, x3, x4, x5, x6, x7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(15)
|
@method_id(15)
|
||||||
fun test_call_1(x: int): (int, int, int, int, int, int, int) {
|
fun test_call_1(x: int): (int, int, int, int, int, int, int) {
|
||||||
return foo1(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
return foo1(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun foo2(x1: int, x2: int, x3456: (int, int, int, int), x7: int): (int, int, int, int, int, int, int) {
|
fun foo2(x1: int, x2: int, x3456: (int, int, int, int), x7: int): (int, int, int, int, int, int, int) {
|
||||||
var (x3: int, x4: int, x5: int, x6: int) = x3456;
|
var (x3: int, x4: int, x5: int, x6: int) = x3456;
|
||||||
return (x1, x2, x3, x4, x5, x6, x7);
|
return (x1, x2, x3, x4, x5, x6, x7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(16)
|
@method_id(16)
|
||||||
fun test_call_2(x: int): (int, int, int, int, int, int, int) {
|
fun test_call_2(x: int): (int, int, int, int, int, int, int) {
|
||||||
return foo2(x, x.`~inc`(x / 20), (x, x = x * 2, x, x += 1), x);
|
return foo2(x, x.`~inc`(x / 20), (x, x = x * 2, x, x += 1), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun asm_func(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int)
|
fun asm_func(x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int): (int, int, int, int, int, int, int)
|
||||||
asm
|
asm (x4 x5 x6 x7 x1 x2 x3->0 1 2 3 4 5 6) "NOP";
|
||||||
(x4 x5 x6 x7 x1 x2 x3->0 1 2 3 4 5 6) "NOP";
|
|
||||||
|
|
||||||
@method_id(17)
|
@method_id(17)
|
||||||
fun test_call_asm_old(x: int): (int, int, int, int, int, int, int) {
|
fun test_call_asm_old(x: int): (int, int, int, int, int, int, int) {
|
||||||
return asm_func(x, x += 1, x, x, x.`~inc`(x / 20), x, x = x * 2);
|
return asm_func(x, x += 1, x, x, x.`~inc`(x / 20), x, x = x * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(18)
|
@method_id(18)
|
||||||
fun test_call_asm_new(x: int): (int, int, int, int, int, int, int) {
|
fun test_call_asm_new(x: int): (int, int, int, int, int, int, int) {
|
||||||
return asm_func(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
return asm_func(x, x.`~inc`(x / 20), x, x = x * 2, x, x += 1, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
global xx: int;
|
global xx: int;
|
||||||
@method_id(19)
|
@method_id(19)
|
||||||
fun test_global(x: int): (int, int, int, int, int, int, int) {
|
fun test_global(x: int) {
|
||||||
xx = x;
|
xx = x;
|
||||||
return (xx, xx.`~inc`(xx / 20), xx, xx = xx * 2, xx, xx += 1, xx);
|
return (x, xx, xx.`~inc`(xx / 20), eq(xx += (x *= 0)), xx = xx * 2, xx, xx += 1, xx, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(20)
|
@method_id(20)
|
||||||
fun test_if_else(x: int): (int, int, int, int, int) {
|
fun test_if_else(x: int): (int, int, int, int, int) {
|
||||||
if (x > 10) {
|
if (x > 10) {
|
||||||
return (x.`~inc`(8), x + 1, x = 1, x <<= 3, x);
|
return (x.`~inc`(8), x + 1, x = 1, x <<= 3, x);
|
||||||
} else {
|
} else {
|
||||||
xx = 9;
|
xx = 9;
|
||||||
return (x, x.`~inc`(-4), x.`~inc`(-1), x >= 1, x = x + xx);
|
return (x, x.`~inc`(-4), x.`~inc`(-1), (x >= 1) as int, x = x + xx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(21)
|
||||||
|
fun test_assign_with_inner(x: int) {
|
||||||
|
return (x, x += 10, [(x, x += 20, eq(x -= 50), x)], eq2((x, x *= eq(x /= 2))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(22)
|
||||||
|
fun test_assign_with_mutate(x: int) {
|
||||||
|
return (x, mul2(mutate x, x += 5), x.`~inc`(mul2(mutate x, x)), x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(23)
|
||||||
|
fun test_assign_tensor(x: (int, int)) {
|
||||||
|
var fs = (0, 0);
|
||||||
|
return (x, x = (20, 30), fs = x.multens((1, 2)), fs.multens(multens(mutate x, (-1, -1))), x, fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
global fs: (int, int);
|
||||||
|
@method_id(24)
|
||||||
|
fun test_assign_tensor_global(x: (int, int)) {
|
||||||
|
fs = (0, 0);
|
||||||
|
return (x, x = (20, 30), fs = x.multens((1, 2)), fs.multens(multens(mutate x, (-1, -1))), x, fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
@ -96,9 +123,13 @@ fun main() {
|
||||||
@testcase | 16 | 100 | 100 50 105 210 210 211 211
|
@testcase | 16 | 100 | 100 50 105 210 210 211 211
|
||||||
@testcase | 17 | 100 | 101 50 106 212 100 101 101
|
@testcase | 17 | 100 | 101 50 106 212 100 101 101
|
||||||
@testcase | 18 | 100 | 210 210 211 211 100 50 105
|
@testcase | 18 | 100 | 210 210 211 211 100 50 105
|
||||||
@testcase | 19 | 100 | 100 50 105 210 210 211 211
|
@testcase | 19 | 100 | 100 100 50 105 210 210 211 211 0
|
||||||
@testcase | 20 | 80 | 80 89 1 8 8
|
@testcase | 20 | 80 | 80 89 1 8 8
|
||||||
@testcase | 20 | 9 | 9 -40 -10 -1 13
|
@testcase | 20 | 9 | 9 -40 -10 -1 13
|
||||||
|
@testcase | 21 | 100 | 100 110 [ 110 130 80 80 ] 80 3200
|
||||||
|
@testcase | 22 | 100 | 100 210 4200 630
|
||||||
|
@testcase | 23 | 1 1 | 1 1 20 30 20 60 -400 -3600 -20 -60 -400 -3600
|
||||||
|
@testcase | 24 | 1 1 | 1 1 20 30 20 60 -400 -3600 -20 -60 -400 -3600
|
||||||
|
|
||||||
@fif_codegen
|
@fif_codegen
|
||||||
"""
|
"""
|
||||||
|
@ -107,5 +138,5 @@ fun main() {
|
||||||
inc CALLDICT // self newY
|
inc CALLDICT // self newY
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
@code_hash 97139400653362069936987769894397430077752335662822462908581556703209313861576
|
@code_hash 7627024945492125068389905298530400936797031708759561372406088054030801992712
|
||||||
*/
|
*/
|
||||||
|
|
28
tolk-tester/tests/assignment-tests.tolk
Normal file
28
tolk-tester/tests/assignment-tests.tolk
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
fun extractFromTypedTuple(params: [int]) {
|
||||||
|
var [payload: int] = params;
|
||||||
|
return payload + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(101)
|
||||||
|
fun test101(x: int) {
|
||||||
|
var params = [x];
|
||||||
|
return extractFromTypedTuple(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun autoInferIntNull(x: int) {
|
||||||
|
if (x > 10) { return null; }
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(value: int) {
|
||||||
|
var (x: int, y) = (autoInferIntNull(value), autoInferIntNull(value * 2));
|
||||||
|
if (x == null && y == null) { return null; }
|
||||||
|
return x == null || y == null ? -1 : x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@testcase | 0 | 3 | 9
|
||||||
|
@testcase | 0 | 6 | -1
|
||||||
|
@testcase | 0 | 11 | (null)
|
||||||
|
@testcase | 101 | 78 | 88
|
||||||
|
*/
|
|
@ -1,20 +1,20 @@
|
||||||
fun lshift(): int {
|
fun lshift(): bool {
|
||||||
return (1 << 0) == 1;
|
return (1 << 0) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rshift(): int {
|
fun rshift(): bool {
|
||||||
return (1 >> 0) == 1;
|
return (1 >> 0) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lshift_var(i: int): int {
|
fun lshift_var(i: int): bool {
|
||||||
return (1 << i) == 1;
|
return (1 << i) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun rshift_var(i: int): int {
|
fun rshift_var(i: int): bool {
|
||||||
return (1 >> i) == 1;
|
return (1 >> i) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(x: int): int {
|
fun main(x: int): bool {
|
||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
return lshift();
|
return lshift();
|
||||||
} else if (x == 1) {
|
} else if (x == 1) {
|
||||||
|
@ -31,12 +31,71 @@ fun main(x: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(11)
|
@method_id(11)
|
||||||
fun is_claimed(index: int): int {
|
fun is_claimed(index: int): bool {
|
||||||
var claim_bit_index: int = index % 256;
|
var claim_bit_index: int = index % 256;
|
||||||
var mask: int = 1 << claim_bit_index;
|
var mask: int = 1 << claim_bit_index;
|
||||||
return (255 & mask) == mask;
|
return (255 & mask) == mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@method_id(12)
|
||||||
|
fun bit_not(i: int, b: bool): (int, bool, bool, bool, int, bool) {
|
||||||
|
var i2 = ~i;
|
||||||
|
var b2 = !b;
|
||||||
|
var (i3: int, b3: bool) = (i2, b2);
|
||||||
|
return (i3, b3, !i, !b, ~~~i, !!!b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(13)
|
||||||
|
fun boolWithBitwiseConst() {
|
||||||
|
var found = true;
|
||||||
|
return (found & false, found | true, found ^ true, found & found);
|
||||||
|
}
|
||||||
|
|
||||||
|
global g14: int;
|
||||||
|
fun getBool() { return (g14 += 1) > 2; }
|
||||||
|
|
||||||
|
@method_id(14)
|
||||||
|
fun boolWithBitwise(b: bool) {
|
||||||
|
g14 = 0;
|
||||||
|
return (b & getBool(), !b & getBool(), b | getBool(), !b | getBool(), b ^ getBool(), !b & getBool(), g14);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(15)
|
||||||
|
fun boolWithBitwiseSet(b1: bool, b2: bool) {
|
||||||
|
b1 &= b2;
|
||||||
|
b2 |= true;
|
||||||
|
b1 |= b1 == false;
|
||||||
|
b2 ^= (b1 ^= b2);
|
||||||
|
return (b1, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(16)
|
||||||
|
fun testDoUntilCodegen(i: bool, n: int) {
|
||||||
|
var cnt = 0;
|
||||||
|
do { cnt += 1; } while (i);
|
||||||
|
do { cnt += 1; } while (!!i);
|
||||||
|
do { cnt += 1; } while (n);
|
||||||
|
return (cnt, !i, !n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(17)
|
||||||
|
fun testConstNegateCodegen() {
|
||||||
|
return (!0, !1, !true, !false, !!true, !!false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(18)
|
||||||
|
fun testBoolNegateOptimized(x: bool) {
|
||||||
|
return (x, !x, !!x, !!!x, !!!!true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun eqX(x: bool) { return x; }
|
||||||
|
|
||||||
|
@method_id(19)
|
||||||
|
fun testBoolCompareOptimized(x: bool) {
|
||||||
|
return (x == true, x != true, eqX(x) == false, eqX(x) != false, !!(x == !false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
method_id | in | out
|
method_id | in | out
|
||||||
|
@ -50,4 +109,96 @@ fun is_claimed(index: int): int {
|
||||||
@testcase | 11 | 1 | -1
|
@testcase | 11 | 1 | -1
|
||||||
@testcase | 11 | 256 | -1
|
@testcase | 11 | 256 | -1
|
||||||
@testcase | 11 | 8 | 0
|
@testcase | 11 | 8 | 0
|
||||||
|
@testcase | 12 | 0 0 | -1 -1 -1 -1 -1 -1
|
||||||
|
@testcase | 12 | -1 -1 | 0 0 0 0 0 0
|
||||||
|
@testcase | 12 | 7 0 | -8 -1 0 -1 -8 -1
|
||||||
|
@testcase | 14 | -1 | 0 0 -1 -1 0 0 6
|
||||||
|
@testcase | 14 | 0 | 0 0 -1 -1 -1 -1 6
|
||||||
|
@testcase | 15 | -1 -1 | 0 -1
|
||||||
|
@testcase | 15 | -1 0 | 0 -1
|
||||||
|
@testcase | 16 | 0 0 | 3 -1 -1
|
||||||
|
@testcase | 17 | | -1 0 0 -1 -1 0
|
||||||
|
@testcase | 18 | 0 | 0 -1 0 -1 -1
|
||||||
|
@testcase | 18 | -1 | -1 0 -1 0 -1
|
||||||
|
@testcase | 19 | 0 | 0 -1 -1 0 0
|
||||||
|
@testcase | 19 | -1 | -1 0 0 -1 -1
|
||||||
|
|
||||||
|
@fif_codegen
|
||||||
|
"""
|
||||||
|
boolWithBitwiseConst PROC:<{
|
||||||
|
//
|
||||||
|
0 PUSHINT // _3
|
||||||
|
-1 PUSHINT // _3 _5
|
||||||
|
0 PUSHINT // _3 _5 _7
|
||||||
|
-1 PUSHINT // _3 _5 _7 _8
|
||||||
|
}>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@fif_codegen
|
||||||
|
"""
|
||||||
|
testDoUntilCodegen PROC:<{
|
||||||
|
// i n
|
||||||
|
0 PUSHINT // i n cnt=0
|
||||||
|
UNTIL:<{
|
||||||
|
INC // i n cnt
|
||||||
|
s2 PUSH // i n cnt i
|
||||||
|
NOT // i n cnt _6
|
||||||
|
}> // i n cnt
|
||||||
|
UNTIL:<{
|
||||||
|
INC // i n cnt
|
||||||
|
s2 PUSH // i n cnt i
|
||||||
|
NOT // i n cnt _9
|
||||||
|
}> // i n cnt
|
||||||
|
UNTIL:<{
|
||||||
|
INC // i n cnt
|
||||||
|
OVER // i n cnt n
|
||||||
|
0 EQINT // i n cnt _12
|
||||||
|
}> // i n cnt
|
||||||
|
s0 s2 XCHG // cnt n i
|
||||||
|
NOT // cnt n _13
|
||||||
|
SWAP // cnt _13 n
|
||||||
|
0 EQINT // cnt _13 _14
|
||||||
|
}>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@fif_codegen
|
||||||
|
"""
|
||||||
|
testConstNegateCodegen PROC:<{
|
||||||
|
//
|
||||||
|
TRUE // _0
|
||||||
|
FALSE // _0 _1
|
||||||
|
FALSE // _0 _1 _2
|
||||||
|
TRUE // _0 _1 _2 _3
|
||||||
|
TRUE // _0 _1 _2 _3 _4
|
||||||
|
FALSE // _0 _1 _2 _3 _4 _5
|
||||||
|
}>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@fif_codegen
|
||||||
|
"""
|
||||||
|
testBoolNegateOptimized PROC:<{
|
||||||
|
// x
|
||||||
|
DUP // x x
|
||||||
|
NOT // x _1
|
||||||
|
OVER // x _1 x
|
||||||
|
NOT // x _1 _2
|
||||||
|
s2 s(-1) PUXC
|
||||||
|
TRUE // x _1 x _2 _3
|
||||||
|
}>
|
||||||
|
"""
|
||||||
|
|
||||||
|
@fif_codegen
|
||||||
|
"""
|
||||||
|
testBoolCompareOptimized PROC:<{
|
||||||
|
// x
|
||||||
|
DUP // x x
|
||||||
|
NOT // x _1
|
||||||
|
OVER // x _1 x
|
||||||
|
eqX CALLDICT // x _1 _2
|
||||||
|
NOT // x _1 _3
|
||||||
|
s2 PUSH // x _1 _3 x
|
||||||
|
eqX CALLDICT // x _1 _3 _4
|
||||||
|
s3 PUSH // x _1 _3 _4 x
|
||||||
|
}>
|
||||||
|
"""
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
global op: (int, int) -> int;
|
global op: (int, int) -> int;
|
||||||
|
|
||||||
fun check_assoc(a: int, b: int, c: int): int {
|
fun check_assoc(a: int, b: int, c: int): bool {
|
||||||
return op(op(a, b), c) == op(a, op(b, c));
|
return op(op(a, b), c) == op(a, op(b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unnamed_args(_: int, _: slice, _: auto): auto {
|
fun unnamed_args(_: int, _: slice, _: int) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(x: int, y: int, z: int): int {
|
fun main(x: int, y: int, z: int): bool {
|
||||||
op = `_+_`;
|
op = `_+_`;
|
||||||
|
if (0) { return null; }
|
||||||
return check_assoc(x, y, z);
|
return check_assoc(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(101)
|
@method_id(101)
|
||||||
fun test101(x: int, z: int): auto {
|
fun test101(x: int, z: int) {
|
||||||
return unnamed_args(x, "asdf", z);
|
return unnamed_args(x, "asdf", z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
fun check_assoc(op: auto, a: int, b: int, c: int) {
|
fun check_assoc(op: (int, int) -> int, a: int, b: int, c: int) {
|
||||||
return op(op(a, b), c) == op(a, op(b, c));
|
return op(op(a, b), c) == op(a, op(b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(x: int, y: int, z: int): int {
|
fun main(x: int, y: int, z: int): bool {
|
||||||
return check_assoc(`_+_`, x, y, z);
|
return check_assoc(`_+_`, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,8 +162,8 @@ fun test13() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(114)
|
@method_id(114)
|
||||||
fun test110(x: int) {
|
fun test110(x: bool) {
|
||||||
var s = beginCell().storeBool(x < 0).storeBool(0).storeBool(x).endCell().beginParse();
|
var s = beginCell().storeBool(x == true).storeBool(false).storeBool(x).endCell().beginParse();
|
||||||
return (s.loadBool(), s.loadBool(), s.loadBool());
|
return (s.loadBool(), s.loadBool(), s.loadBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,15 +179,15 @@ fun test111() {
|
||||||
if (s.addressIsNone()) {
|
if (s.addressIsNone()) {
|
||||||
s.skipBits(2);
|
s.skipBits(2);
|
||||||
}
|
}
|
||||||
if (s.loadBool() == 0) {
|
if (s.loadBool() == false) {
|
||||||
assert(s.loadBool() == 0) throw 444;
|
assert(!s.loadBool()) throw 444;
|
||||||
s.skipBouncedPrefix();
|
s.skipBouncedPrefix();
|
||||||
}
|
}
|
||||||
var op2 = s.loadMessageOp();
|
var op2 = s.loadMessageOp();
|
||||||
var q2 = s.loadMessageQueryId();
|
var q2 = s.loadMessageQueryId();
|
||||||
s.skipBits(64);
|
s.skipBits(64);
|
||||||
s.assertEndOfSlice();
|
s.assertEndOfSlice();
|
||||||
assert(isMessageBounced(0x001)) throw 444;
|
assert(isMessageBounced(0x001) && !isMessageBounced(0x002)) throw 444;
|
||||||
return (op1, q1, op2, q2);
|
return (op1, q1, op2, q2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,15 +216,15 @@ Note, that since 'compute-asm-ltr' became on be default, chaining methods codege
|
||||||
"""
|
"""
|
||||||
test6 PROC:<{
|
test6 PROC:<{
|
||||||
//
|
//
|
||||||
NEWC // _1
|
NEWC // _0
|
||||||
1 PUSHINT // _1 _2=1
|
1 PUSHINT // _0 _1=1
|
||||||
SWAP // _2=1 _1
|
SWAP // _1=1 _0
|
||||||
32 STU // _0
|
32 STU // _0
|
||||||
2 PUSHINT // _0 _6=2
|
2 PUSHINT // _0 _5=2
|
||||||
SWAP // _6=2 _0
|
SWAP // _5=2 _0
|
||||||
32 STU // _0
|
32 STU // _0
|
||||||
3 PUSHINT // _0 _10=3
|
3 PUSHINT // _0 _9=3
|
||||||
SWAP // _10=3 _0
|
SWAP // _9=3 _0
|
||||||
32 STU // _0
|
32 STU // _0
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@method_id(101)
|
@method_id(101)
|
||||||
fun test1(): int {
|
fun test1(): int {
|
||||||
var x = false;
|
var x: int = false as int;
|
||||||
if (x == true) {
|
if (x == true as int) {
|
||||||
x= 100500;
|
x= 100500;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
|
@ -35,7 +35,7 @@ Below, I just give examples of @fif_codegen tag:
|
||||||
"""
|
"""
|
||||||
main PROC:<{
|
main PROC:<{
|
||||||
// s
|
// s
|
||||||
17 PUSHINT // s _3=17
|
17 PUSHINT // s _1=17
|
||||||
OVER // s z=17 t
|
OVER // s z=17 t
|
||||||
WHILE:<{
|
WHILE:<{
|
||||||
...
|
...
|
||||||
|
|
150
tolk-tester/tests/generics-1.tolk
Normal file
150
tolk-tester/tests/generics-1.tolk
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
fun eq1<X>(value: X): X { return value; }
|
||||||
|
fun eq2<X>(value: X) { return value; }
|
||||||
|
fun eq3<X>(value: X): X { var cp: [X] = [eq1(value)]; var ((([v: X]))) = cp; return v; }
|
||||||
|
fun eq4<X>(value: X) { return eq1<X>(value); }
|
||||||
|
|
||||||
|
@method_id(101)
|
||||||
|
fun test101(x: int) {
|
||||||
|
var (a, b, c) = (x, (x,x), [x,x]);
|
||||||
|
return (eq1(a), eq1(b), eq1(c), eq2(a), eq2(b), eq2(c), eq3(a), eq4(b), eq3(createEmptyTuple()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTwo<X>(): X { return 2 as X; }
|
||||||
|
|
||||||
|
fun takeInt(a: int) { return a; }
|
||||||
|
|
||||||
|
@method_id(102)
|
||||||
|
fun test102(): (int, int, int, [(int, int)]) {
|
||||||
|
var a: int = getTwo();
|
||||||
|
var _: int = getTwo();
|
||||||
|
var b = getTwo() as int;
|
||||||
|
var c: int = 1 ? getTwo() : getTwo();
|
||||||
|
var c redef = getTwo();
|
||||||
|
return (eq1<int>(a), eq2<int>(b), takeInt(getTwo()), [(getTwo(), getTwo())]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(103)
|
||||||
|
fun test103(first: int): (int, int, int) {
|
||||||
|
var t = createEmptyTuple();
|
||||||
|
var cs = beginCell().storeInt(100, 32).endCell().beginParse();
|
||||||
|
t.tuplePush(first);
|
||||||
|
t.tuplePush(2);
|
||||||
|
t.tuplePush(cs);
|
||||||
|
cs = t.tupleAt(2);
|
||||||
|
cs = t.tupleAt(2) as slice;
|
||||||
|
return (t.tupleAt(0), cs.loadInt(32), t.tupleAt<slice>(2).loadInt(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
fun manyEq<T1, T2, T3>(a: T1, b: T2, c: T3): [T1, T2, T3] {
|
||||||
|
return [a, b, c];
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(104)
|
||||||
|
fun test104(f: int) {
|
||||||
|
return (
|
||||||
|
manyEq(1 ? 1 : 1, f ? 0 : null, !f ? getTwo() as int : null),
|
||||||
|
manyEq((f ? null as int : eq2(2), beginCell().storeBool(true).endCell().beginParse().loadBool()), 0, eq4(f))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calcSum<X>(x: X, y: X) { return x + y; }
|
||||||
|
|
||||||
|
@method_id(105)
|
||||||
|
fun test105() {
|
||||||
|
if (0) { calcSum(((0)), null); }
|
||||||
|
return (calcSum(1, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
fun calcYPlus1<Y>(value: Y) { return value + 1; }
|
||||||
|
fun calcLoad32(cs: slice) { return cs.loadInt(32); }
|
||||||
|
fun calcTensorPlus1(tens: (int, int)) { var (f, s) = tens; return (f + 1, s + 1); }
|
||||||
|
fun calcTensorMul2(tens: (int, int)) { var (f, s) = tens; return (f * 2, s * 2); }
|
||||||
|
fun cellToSlice(c: cell) { return c.beginParse(); }
|
||||||
|
fun abstractTransform<X, Y, R>(xToY: (X) -> Y, yToR: (((Y))) -> R, initialX: X): R {
|
||||||
|
var y = xToY(initialX);
|
||||||
|
return yToR(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(106)
|
||||||
|
fun test106() {
|
||||||
|
var c = beginCell().storeInt(106, 32).endCell();
|
||||||
|
return [
|
||||||
|
abstractTransform(cellToSlice, calcLoad32, c),
|
||||||
|
abstractTransform(calcYPlus1<int>, calcYPlus1<int>, 0),
|
||||||
|
abstractTransform(calcTensorPlus1, calcTensorMul2, (2, 2))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callTupleFirst<X, Y>(t: X): Y { return t.tupleFirst(); }
|
||||||
|
fun callTuplePush<T, V>(mutate self: T, v1: V, v2: V): self { self.tuplePush(v1); tuplePush(mutate self, v2); return self; }
|
||||||
|
fun getTupleLastInt(t: tuple) { return t.tupleLast<int>(); }
|
||||||
|
fun getTupleSize(t: tuple) { return t.tupleSize(); }
|
||||||
|
fun callAnyFn<TObj, TResult>(f: (TObj) -> TResult, arg: TObj) { return f(arg); }
|
||||||
|
fun callAnyFn2<TCallback>(f: TCallback, arg: tuple) { return f(arg); }
|
||||||
|
|
||||||
|
global t107: tuple;
|
||||||
|
|
||||||
|
@method_id(107)
|
||||||
|
fun test107() {
|
||||||
|
t107 = createEmptyTuple();
|
||||||
|
callTuplePush(mutate t107, 1, 2);
|
||||||
|
t107.callTuplePush(3, 4).callTuplePush(5, 6);
|
||||||
|
var first: int = t107.callTupleFirst();
|
||||||
|
return (
|
||||||
|
callAnyFn<tuple, int>(getTupleSize, t107),
|
||||||
|
callAnyFn2(getTupleSize, t107),
|
||||||
|
first,
|
||||||
|
callTupleFirst(t107) as int,
|
||||||
|
callAnyFn(getTupleLastInt, t107),
|
||||||
|
callAnyFn2(getTupleLastInt, t107)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
global g108: int;
|
||||||
|
|
||||||
|
fun inc108(by: int) { g108 += by; }
|
||||||
|
fun getInc108() { return inc108; }
|
||||||
|
fun returnResult<RetT>(f: () -> RetT): RetT { return f(); }
|
||||||
|
fun applyAndReturn<ArgT, RetT>(f: () -> (ArgT) -> RetT, arg: ArgT): () -> ArgT -> RetT {
|
||||||
|
f()(arg);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(108)
|
||||||
|
fun test108() {
|
||||||
|
g108 = 0;
|
||||||
|
getInc108()(1);
|
||||||
|
returnResult<(int) -> void>(getInc108)(2);
|
||||||
|
applyAndReturn<int, void>(getInc108, 10)()(10);
|
||||||
|
returnResult(getInc108)(2);
|
||||||
|
applyAndReturn(getInc108, 10)()(10);
|
||||||
|
return g108;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main(x: int): (int, [[int, int]]) {
|
||||||
|
try { if(x) { throw (1, x); } }
|
||||||
|
catch (excNo, arg) { return (arg as int, [[eq2(arg as int), getTwo()]]); }
|
||||||
|
return (0, [[x, 1]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@testcase | 0 | 1 | 1 [ [ 1 2 ] ]
|
||||||
|
@testcase | 101 | 0 | 0 0 0 [ 0 0 ] 0 0 0 [ 0 0 ] 0 0 0 []
|
||||||
|
@testcase | 102 | | 2 2 2 [ 2 2 ]
|
||||||
|
@testcase | 103 | 0 | 0 100 100
|
||||||
|
@testcase | 104 | 0 | [ 1 (null) 2 ] [ 2 -1 0 0 ]
|
||||||
|
@testcase | 105 | | 3
|
||||||
|
@testcase | 106 | | [ 106 2 6 6 ]
|
||||||
|
@testcase | 107 | | 6 6 1 1 6 6
|
||||||
|
@testcase | 108 | | 45
|
||||||
|
|
||||||
|
@fif_codegen DECLPROC eq1<int>
|
||||||
|
@fif_codegen DECLPROC eq1<tuple>
|
||||||
|
@fif_codegen DECLPROC eq1<(int,int)>
|
||||||
|
@fif_codegen DECLPROC eq1<[int,int]>
|
||||||
|
@fif_codegen DECLPROC getTwo<int>
|
||||||
|
|
||||||
|
@fif_codegen_avoid DECLPROC eq1
|
||||||
|
@fif_codegen_avoid DECLPROC eq2
|
||||||
|
@fif_codegen_avoid DECLPROC eq3
|
||||||
|
*/
|
|
@ -11,7 +11,7 @@ fun prepareDict_3_30_4_40_5_x(valueAt5: int): cell {
|
||||||
fun lookupIdxByValue(idict32: cell, value: int): int {
|
fun lookupIdxByValue(idict32: cell, value: int): int {
|
||||||
var cur_key = -1;
|
var cur_key = -1;
|
||||||
do {
|
do {
|
||||||
var (cur_key redef, cs: slice, found: int) = idict32.iDictGetNext(32, cur_key);
|
var (cur_key redef, cs: slice, found: bool) = idict32.iDictGetNext(32, cur_key);
|
||||||
// one-line condition (via &) doesn't work, since right side is calculated immediately
|
// one-line condition (via &) doesn't work, since right side is calculated immediately
|
||||||
if (found) {
|
if (found) {
|
||||||
if (cs.loadInt(32) == value) {
|
if (cs.loadInt(32) == value) {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
fun main() {
|
const asdf = 1;
|
||||||
return true();
|
|
||||||
|
fun main(x: int) {
|
||||||
|
return x.asdf();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
The message is weird now, but later I'll rework error messages anyway.
|
@stderr calling a non-function
|
||||||
@stderr cannot apply expression of type int to an expression of type (): cannot unify type () -> ??3 with int
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -8,6 +8,6 @@ fun main() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr rvalue expected
|
@stderr `_` can't be used as a value; it's a placeholder for a left side of assignment
|
||||||
@stderr inc(_)
|
@stderr inc(_)
|
||||||
*/
|
*/
|
||||||
|
|
10
tolk-tester/tests/invalid-call-9.tolk
Normal file
10
tolk-tester/tests/invalid-call-9.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun getOne() { return 1; }
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
return getOne<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr calling a not generic function with generic T
|
||||||
|
*/
|
8
tolk-tester/tests/invalid-const-1.tolk
Normal file
8
tolk-tester/tests/invalid-const-1.tolk
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fun main() {
|
||||||
|
return 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr invalid integer constant
|
||||||
|
*/
|
13
tolk-tester/tests/invalid-declaration-11.tolk
Normal file
13
tolk-tester/tests/invalid-declaration-11.tolk
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// this function is declared incorrectly,
|
||||||
|
// since it should return 2 values onto a stack (1 for returned slice, 1 for mutated int)
|
||||||
|
// but contains not 2 numbers in asm ret_order
|
||||||
|
fun loadAddress2(mutate self: int): slice
|
||||||
|
asm( -> 1 0 2) "LDMSGADDR";
|
||||||
|
|
||||||
|
fun main(){}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr ret_order (after ->) expected to contain 2 numbers
|
||||||
|
@stderr asm( -> 1 0 2)
|
||||||
|
*/
|
16
tolk-tester/tests/invalid-declaration-12.tolk
Normal file
16
tolk-tester/tests/invalid-declaration-12.tolk
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
fun proxy(x: int) {
|
||||||
|
return factorial(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun factorial(x: int) {
|
||||||
|
if (x <= 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return x * proxy(x-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr could not infer return type of `factorial`, because it appears in a recursive call chain
|
||||||
|
@stderr fun factorial
|
||||||
|
*/
|
7
tolk-tester/tests/invalid-declaration-13.tolk
Normal file
7
tolk-tester/tests/invalid-declaration-13.tolk
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const c: slice = 123 + 456;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr expression type does not match declared type
|
||||||
|
@stderr const c
|
||||||
|
*/
|
10
tolk-tester/tests/invalid-generics-1.tolk
Normal file
10
tolk-tester/tests/invalid-generics-1.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun f<X>(v: int, x: X) {}
|
||||||
|
|
||||||
|
fun failCantDeduceWithoutArgument() {
|
||||||
|
return f(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not deduce X for generic function `f<X>`
|
||||||
|
*/
|
9
tolk-tester/tests/invalid-generics-10.tolk
Normal file
9
tolk-tester/tests/invalid-generics-10.tolk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fun invalidReferencingGenericMethodWithoutGeneric() {
|
||||||
|
var t = createEmptyTuple();
|
||||||
|
var cb = t.tupleLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not use a generic function `tupleLast<T>` as non-call
|
||||||
|
*/
|
11
tolk-tester/tests/invalid-generics-11.tolk
Normal file
11
tolk-tester/tests/invalid-generics-11.tolk
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
global gVar: int;
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
var x = gVar<int>;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr generic T not expected here
|
||||||
|
*/
|
10
tolk-tester/tests/invalid-generics-2.tolk
Normal file
10
tolk-tester/tests/invalid-generics-2.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun f<T>(v: int, x: T) {}
|
||||||
|
|
||||||
|
fun failCantDeduceWithPlainNull() {
|
||||||
|
return f(0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not deduce T for generic function `f<T>`
|
||||||
|
*/
|
11
tolk-tester/tests/invalid-generics-3.tolk
Normal file
11
tolk-tester/tests/invalid-generics-3.tolk
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fun f<T>(x: T, y: T) {}
|
||||||
|
|
||||||
|
fun failIncompatibleTypesForT() {
|
||||||
|
return f(32, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr T is both int and slice for generic function `f<T>`
|
||||||
|
@stderr f(32
|
||||||
|
*/
|
10
tolk-tester/tests/invalid-generics-4.tolk
Normal file
10
tolk-tester/tests/invalid-generics-4.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun f<T>(x: T): void asm "NOP";
|
||||||
|
|
||||||
|
fun failInstantiatingAsmFunctionWithNon1Slot() {
|
||||||
|
f((1, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not call `f<T>` with T=(int, int), because it occupies 2 stack slots in TVM, not 1
|
||||||
|
*/
|
10
tolk-tester/tests/invalid-generics-5.tolk
Normal file
10
tolk-tester/tests/invalid-generics-5.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun f<T>(x: T): void asm "NOP";
|
||||||
|
|
||||||
|
fun failUsingGenericFunctionPartially() {
|
||||||
|
var cb = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not use a generic function `f<T>` as non-call
|
||||||
|
*/
|
10
tolk-tester/tests/invalid-generics-6.tolk
Normal file
10
tolk-tester/tests/invalid-generics-6.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun eq<X>(t: X) { return t; }
|
||||||
|
|
||||||
|
fun failUsingGenericFunctionPartially() {
|
||||||
|
var cb = createEmptyTuple().eq().eq().tuplePush;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not use a generic function `tuplePush<T>` as non-call
|
||||||
|
*/
|
18
tolk-tester/tests/invalid-generics-7.tolk
Normal file
18
tolk-tester/tests/invalid-generics-7.tolk
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
fun failOnInstantiation(a: slice) {
|
||||||
|
var b: slice = foo(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar<X>(value: X) : X {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fun foo<X>(value: X) : X {
|
||||||
|
return bar(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr while instantiating generic function `foo<slice>`
|
||||||
|
@stderr while instantiating generic function `bar<slice>`
|
||||||
|
@stderr can not convert type `int` to return type `slice`
|
||||||
|
@stderr return 1
|
||||||
|
*/
|
11
tolk-tester/tests/invalid-generics-8.tolk
Normal file
11
tolk-tester/tests/invalid-generics-8.tolk
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fun withT1T2<T1, T2>(a: (T1, T2)) {}
|
||||||
|
|
||||||
|
fun wrongTCountPassed() {
|
||||||
|
withT1T2<int>((5, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr wrong count of generic T: expected 2, got 1
|
||||||
|
@stderr <int>
|
||||||
|
*/
|
8
tolk-tester/tests/invalid-generics-9.tolk
Normal file
8
tolk-tester/tests/invalid-generics-9.tolk
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fun invalidProvidingGenericTsToNotGeneric() {
|
||||||
|
beginCell<builder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr calling a not generic function with generic T
|
||||||
|
*/
|
|
@ -7,5 +7,5 @@ fun cantAssignToVal() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `x`
|
@stderr modifying immutable variable `x`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,5 +4,5 @@ fun load32(self: slice): int {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying `self` (call a mutating method), which is immutable by default
|
@stderr modifying `self`, which is immutable by default
|
||||||
*/
|
*/
|
||||||
|
|
9
tolk-tester/tests/invalid-mutate-16.tolk
Normal file
9
tolk-tester/tests/invalid-mutate-16.tolk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fun cantCallMutatingFunctionWithAssignmentLValue() {
|
||||||
|
var t: tuple = createEmptyTuple();
|
||||||
|
(t = createEmptyTuple()).tuplePush(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr assignment can not be used as lvalue
|
||||||
|
*/
|
13
tolk-tester/tests/invalid-mutate-17.tolk
Normal file
13
tolk-tester/tests/invalid-mutate-17.tolk
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
@pure
|
||||||
|
fun tupleMut(mutate self: tuple): int
|
||||||
|
asm "TLEN";
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
var t = createEmptyTuple();
|
||||||
|
return [[t.tupleMut]];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr saving `tupleMut` into a variable is impossible, since it has `mutate` parameters
|
||||||
|
*/
|
|
@ -6,5 +6,5 @@ fun cantAssignToVal() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `x`
|
@stderr modifying immutable variable `x`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,5 +7,5 @@ fun cantAssignToConst() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `op_increase`
|
@stderr modifying immutable constant
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,5 +10,5 @@ fun cantPassToMutatingFunction() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `myVal`
|
@stderr modifying immutable variable `myVal`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,6 +9,6 @@ fun cantCallMutatingMethod(c: cell) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `s` (call a mutating method)
|
@stderr modifying immutable variable `s`
|
||||||
@stderr s.loadUint
|
@stderr s.loadUint
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,6 +11,6 @@ fun cantCallMutatingFunctionWithImmutable() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `op_increase` (call a mutating function)
|
@stderr modifying immutable constant
|
||||||
@stderr inc(mutate op_increase)
|
@stderr inc(mutate op_increase)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,6 +10,6 @@ fun cantCallMutatingFunctionWithRvalue() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr lvalue expected (call a mutating function)
|
@stderr literal can not be used as lvalue
|
||||||
@stderr incBoth(mutate x, mutate 30)
|
@stderr incBoth(mutate x, mutate 30)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,5 +6,5 @@ fun cantRedefImmutable() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying an immutable variable `x` (left side of assignment)
|
@stderr `redef` for immutable variable
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,6 +4,6 @@ fun increment(self: int) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr modifying `self` (left side of assignment), which is immutable by default
|
@stderr modifying `self`, which is immutable by default
|
||||||
@stderr probably, you want to declare `mutate self`
|
@stderr probably, you want to declare `mutate self`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,5 +4,5 @@ fun load_u32(cs: slice): (slice, int) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr expected `(`, got `32`
|
@stderr expected `;`, got `32`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,7 @@ fun f_pure(): int {
|
||||||
return f_impure();
|
return f_impure();
|
||||||
}
|
}
|
||||||
|
|
||||||
fun f_impure(): int {}
|
fun f_impure(): int { return 0; }
|
||||||
|
|
||||||
fun main(): int {
|
fun main(): int {
|
||||||
return f_pure();
|
return f_pure();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
fun validate_input(input: cell): (int, int) {
|
fun validate_input(input: cell): (int, int) {
|
||||||
var (x, y, z, correct) = calculateCellSize(input, 10);
|
var (x, y, z, correct) = calculateCellSize(input, 10);
|
||||||
assert(correct) throw 102;
|
assert(correct) throw 102;
|
||||||
|
return (x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
|
|
10
tolk-tester/tests/invalid-redefinition-6.tolk
Normal file
10
tolk-tester/tests/invalid-redefinition-6.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
const s1 = "asdf";
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
var s1 redef = "d";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr `redef` for unknown variable
|
||||||
|
*/
|
|
@ -4,6 +4,6 @@ fun cantReturnNothingFromSelf(mutate self: int): self {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr missing return; forgot `return self`?
|
@stderr missing return
|
||||||
@stderr }
|
@stderr }
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,5 +4,5 @@ fun main(x: int) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr null is not a function: use `null`, not `null()`
|
@stderr calling a non-function
|
||||||
*/
|
*/
|
||||||
|
|
9
tolk-tester/tests/invalid-syntax-6.tolk
Normal file
9
tolk-tester/tests/invalid-syntax-6.tolk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fun main() {
|
||||||
|
var a = 1;
|
||||||
|
(a += 1) += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr assignment can not be used as lvalue
|
||||||
|
*/
|
9
tolk-tester/tests/invalid-syntax-7.tolk
Normal file
9
tolk-tester/tests/invalid-syntax-7.tolk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fun main() {
|
||||||
|
var x = 1;
|
||||||
|
x += (var y = 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr expected <expression>, got `var`
|
||||||
|
*/
|
|
@ -6,5 +6,5 @@ fun main() {
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr .tolk:2
|
@stderr .tolk:2
|
||||||
@stderr expected <type>, got `scli`
|
@stderr unknown type name `scli`
|
||||||
*/
|
*/
|
||||||
|
|
8
tolk-tester/tests/invalid-typing-10.tolk
Normal file
8
tolk-tester/tests/invalid-typing-10.tolk
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fun failMathOnBoolean(c: cell) {
|
||||||
|
return (null == c) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not apply operator `*` to `bool` and `int`
|
||||||
|
*/
|
11
tolk-tester/tests/invalid-typing-11.tolk
Normal file
11
tolk-tester/tests/invalid-typing-11.tolk
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
fun failBitwiseNotOnBool() {
|
||||||
|
var eq = 1 == 0;
|
||||||
|
if (~eq) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not apply operator `~` to `bool`
|
||||||
|
*/
|
10
tolk-tester/tests/invalid-typing-12.tolk
Normal file
10
tolk-tester/tests/invalid-typing-12.tolk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
fun failAssignNullToTensor() {
|
||||||
|
var ab = (1, 2);
|
||||||
|
ab = null;
|
||||||
|
return ab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not assign `null` to variable of type `(int, int)`
|
||||||
|
*/
|
|
@ -1,9 +1,9 @@
|
||||||
fun main() {
|
fun main() {
|
||||||
var tri: (int, bool) = (10, false);
|
var tri: (int, int) = (10, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr bool type is not supported yet
|
@stderr can not assign `(int, bool)` to variable of type `(int, int)`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,5 +15,5 @@ fun cantMixDifferentThis() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr cannot apply function appendBuilder : builder -> (builder, ()) to arguments of type int: cannot unify type int with builder
|
@stderr can not call method for `builder` with object of type `int`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,8 +7,6 @@ fun cantCallNotChainedMethodsInAChain(x: int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The error is very weird, but nevertheless, the type system prevents of doing such errors.
|
|
||||||
|
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr cannot apply function incNotChained : int -> (int, ()) to arguments of type (): cannot unify type () with int
|
@stderr can not call method for `int` with object of type `void`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -7,8 +7,7 @@ fun failWhenReturnANotChainedValue(x: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The error is very weird, but nevertheless, the type system prevents of doing such errors.
|
|
||||||
|
|
||||||
@compilation_should_fail
|
@compilation_should_fail
|
||||||
@stderr previous function return type int cannot be unified with return statement expression type (): cannot unify type () with int
|
@stderr x.incNotChained()
|
||||||
|
@stderr can not convert type `void` to return type `int`
|
||||||
*/
|
*/
|
||||||
|
|
8
tolk-tester/tests/invalid-typing-6.tolk
Normal file
8
tolk-tester/tests/invalid-typing-6.tolk
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fun failWhenTernaryConditionNotInt(cs: slice) {
|
||||||
|
return cs ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not use `slice` as a boolean condition
|
||||||
|
*/
|
9
tolk-tester/tests/invalid-typing-7.tolk
Normal file
9
tolk-tester/tests/invalid-typing-7.tolk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fun failAssignPlainNullToVariable() {
|
||||||
|
var x = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not infer type of `x`, it's always null
|
||||||
|
@stderr specify its type with `x: <type>` or use `null as <type>`
|
||||||
|
*/
|
8
tolk-tester/tests/invalid-typing-8.tolk
Normal file
8
tolk-tester/tests/invalid-typing-8.tolk
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
fun failExplicitCastIncompatible(c: cell) {
|
||||||
|
return c as slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr type `cell` can not be cast to `slice`
|
||||||
|
*/
|
13
tolk-tester/tests/invalid-typing-9.tolk
Normal file
13
tolk-tester/tests/invalid-typing-9.tolk
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
fun getTupleLastGetter<X>(): tuple -> X {
|
||||||
|
return tupleLast<X>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun failTypeMismatch() {
|
||||||
|
var t = createEmptyTuple();
|
||||||
|
var c: cell = getTupleLastGetter<int>()(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@compilation_should_fail
|
||||||
|
@stderr can not assign `int` to variable of type `cell`
|
||||||
|
*/
|
|
@ -1,14 +1,14 @@
|
||||||
import "imports/use-dicts.tolk"
|
import "imports/use-dicts.tolk"
|
||||||
|
|
||||||
fun simpleAllConst() {
|
fun simpleAllConst() {
|
||||||
return (!0, !!0 & !false, !!!0, !1, !!1, !-1, !!-1, (!5 == 0) == !0, !0 == true);
|
return (!0, !!0 & !false, !!!0, !1, !!1, !-1, !!-1, (!5 as int == 0) == !0, !0 == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compileTimeEval1(x: int) {
|
fun compileTimeEval1(x: int) {
|
||||||
// todo now compiler doesn't understand that bool can't be equal to number other than 0/-1
|
// todo now compiler doesn't understand that bool can't be equal to number other than 0/-1
|
||||||
// (but understands that it can't be positive)
|
// (but understands that it can't be positive)
|
||||||
// that's why for now, the last condition is evaluated at runtime
|
// that's why for now, the last condition is evaluated at runtime
|
||||||
return (!x, !x > 10, !x < 10, !!x == 5, !x == -10);
|
return (!x, !x as int > 10, (!x as int) < 10, !!x as int == 5, !x as int == -10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(101)
|
@method_id(101)
|
||||||
|
@ -23,13 +23,13 @@ fun withAndOr(x: int, y: int, z: int) {
|
||||||
var return_at_end = -1;
|
var return_at_end = -1;
|
||||||
if (!x & !y) {
|
if (!x & !y) {
|
||||||
if (!z & !y) { return 10; }
|
if (!z & !y) { return 10; }
|
||||||
else if (z | !!y) { return_at_end = 20; }
|
else if ((z != 0) | !!y) { return_at_end = 20; }
|
||||||
} else if (!!x & !!y & !z) {
|
} else if (!!x & !!y & !z) {
|
||||||
if (!z & (x > 10)) { return_at_end = 30; }
|
if (!z & (x > 10)) { return_at_end = 30; }
|
||||||
if ((x != 11) & !z) { return 40; }
|
if ((x != 11) & !z) { return 40; }
|
||||||
return_at_end = 50;
|
return_at_end = 50;
|
||||||
} else {
|
} else {
|
||||||
return_at_end = !x ? !y : !z | 1;
|
return_at_end = !x ? !y as int : (!z as int) | 1;
|
||||||
}
|
}
|
||||||
return return_at_end;
|
return return_at_end;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,8 @@ fun testDict(last: int) {
|
||||||
|
|
||||||
@method_id(105)
|
@method_id(105)
|
||||||
fun testNotNull(x: int) {
|
fun testNotNull(x: int) {
|
||||||
return [x == null, null == x, !(x == null), null == null, +(null != null)];
|
// return [x == null, null == x, !(x == null), null == null, +(null != null)];
|
||||||
|
return [x == null, null == x, !(x == null)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(106)
|
@method_id(106)
|
||||||
|
@ -123,6 +124,31 @@ fun testLogicalOps2(first: int) {
|
||||||
return (s.getRemainingBitsCount(), sum);
|
return (s.getRemainingBitsCount(), sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@method_id(112)
|
||||||
|
fun mixLogicalIntsAndBools(first: int, cond: bool) {
|
||||||
|
return (
|
||||||
|
(first && cond) || (!first && cond),
|
||||||
|
((first & -1) & cond as int) == ((first && true) && cond) as int,
|
||||||
|
7 && cond,
|
||||||
|
first || cond || !cond || alwaysThrows(),
|
||||||
|
cond || first || !first || alwaysThrows()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(113)
|
||||||
|
fun testConvertIfToIfnot(x: bool) {
|
||||||
|
assert(!!(x == false), 100);
|
||||||
|
assert(!x, 100);
|
||||||
|
if (x == !!false) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!!(x != !false)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
assert(!!x, 100);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -144,8 +170,8 @@ fun main() {
|
||||||
@testcase | 104 | 50 | 3 5 -1
|
@testcase | 104 | 50 | 3 5 -1
|
||||||
@testcase | 104 | 100 | 3 5 5
|
@testcase | 104 | 100 | 3 5 5
|
||||||
@testcase | 104 | 0 | 3 -1 5
|
@testcase | 104 | 0 | 3 -1 5
|
||||||
@testcase | 105 | 0 | [ 0 0 -1 -1 0 ]
|
@testcase | 105 | 0 | [ 0 0 -1 ]
|
||||||
@testcase | 105 | null | [ -1 -1 0 -1 0 ]
|
@testcase | 105 | null | [ -1 -1 0 ]
|
||||||
@testcase | 106 | | [ 0 0 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ 0 -1 ]
|
@testcase | 106 | | [ 0 0 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ 0 -1 ]
|
||||||
@testcase | 107 | | [ -1 -1 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ -1 0 ]
|
@testcase | 107 | | [ -1 -1 0 -1 ] [ 0 0 0 ] [ -1 -1 -1 ] [ -1 0 ]
|
||||||
@testcase | 108 | 1 2 | -1
|
@testcase | 108 | 1 2 | -1
|
||||||
|
@ -159,18 +185,21 @@ fun main() {
|
||||||
@testcase | 110 | 500 | -1 -1 0 -1 -1 3
|
@testcase | 110 | 500 | -1 -1 0 -1 -1 3
|
||||||
@testcase | 111 | 0 | 32 4
|
@testcase | 111 | 0 | 32 4
|
||||||
@testcase | 111 | -1 | 0 8
|
@testcase | 111 | -1 | 0 8
|
||||||
|
@testcase | 112 | 5 0 | 0 -1 0 -1 -1
|
||||||
|
@testcase | 112 | 0 -1 | -1 -1 -1 -1 -1
|
||||||
|
@testcase | 113 | 0 | 1
|
||||||
|
|
||||||
@fif_codegen
|
@fif_codegen
|
||||||
"""
|
"""
|
||||||
simpleAllConst PROC:<{
|
simpleAllConst PROC:<{
|
||||||
//
|
//
|
||||||
-1 PUSHINT
|
TRUE
|
||||||
0 PUSHINT
|
0 PUSHINT
|
||||||
-1 PUSHINT
|
TRUE
|
||||||
0 PUSHINT
|
FALSE
|
||||||
-1 PUSHINT
|
TRUE
|
||||||
0 PUSHINT
|
FALSE
|
||||||
-1 PUSHINT
|
TRUE
|
||||||
TRUE
|
TRUE
|
||||||
TRUE
|
TRUE
|
||||||
}>
|
}>
|
||||||
|
@ -292,4 +321,27 @@ These are moments of future optimizations. For now, it's more than enough.
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@fif_codegen
|
||||||
|
"""
|
||||||
|
testConvertIfToIfnot PROC:<{
|
||||||
|
// x
|
||||||
|
DUP // x x
|
||||||
|
100 THROWIF
|
||||||
|
DUP // x x
|
||||||
|
100 THROWIF
|
||||||
|
DUP // x x
|
||||||
|
IFNOTJMP:<{ // x
|
||||||
|
DROP //
|
||||||
|
1 PUSHINT // _7=1
|
||||||
|
}> // x
|
||||||
|
DUP // x x
|
||||||
|
IFNOTJMP:<{ // x
|
||||||
|
DROP //
|
||||||
|
1 PUSHINT // _8=1
|
||||||
|
}> // x
|
||||||
|
100 THROWIFNOT
|
||||||
|
-4 PUSHINT // _12=-4
|
||||||
|
}>
|
||||||
|
"""
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -118,12 +118,19 @@ fun updateTwoItems(mutate self: (int, int), byValue: int) {
|
||||||
self = (first + byValue, second + byValue);
|
self = (first + byValue, second + byValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global t107_1: int;
|
||||||
|
global t107_2: int;
|
||||||
|
|
||||||
@method_id(107)
|
@method_id(107)
|
||||||
fun testMutableTensor() {
|
fun testMutableTensor() {
|
||||||
var t = (40, 50);
|
var t = (40, 50);
|
||||||
t.updateTwoItems(10);
|
t.updateTwoItems(10);
|
||||||
updateTwoItems(mutate t, 10);
|
updateTwoItems(mutate t, 10);
|
||||||
return t;
|
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
|
@pure
|
||||||
|
@ -147,7 +154,7 @@ fun getSumOfNumbersInCell(c: cell): int {
|
||||||
|
|
||||||
@method_id(110)
|
@method_id(110)
|
||||||
fun testStoreChaining() {
|
fun testStoreChaining() {
|
||||||
var b = beginCell().storeUint(1, 32).storeUint(2, 32).storeUint(3, 32);
|
var b = ((beginCell()).storeUint(1, 32)).storeUint(2, 32).storeUint(3, 32);
|
||||||
b.storeUint(4, 32);
|
b.storeUint(4, 32);
|
||||||
b.myStoreUint(5, 32).storeUint(6, 32);
|
b.myStoreUint(5, 32).storeUint(6, 32);
|
||||||
storeUint(mutate b, 7, 32);
|
storeUint(mutate b, 7, 32);
|
||||||
|
@ -191,7 +198,7 @@ fun testStoreAndMutateBoth() {
|
||||||
b.myStoreU32_and_mutate_x(mutate x);
|
b.myStoreU32_and_mutate_x(mutate x);
|
||||||
|
|
||||||
var cs: slice = b.endCell().beginParse();
|
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));
|
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;
|
assert(n5 == x) throw 100;
|
||||||
|
|
||||||
return [n1,n2,n3,n4,n5];
|
return [n1,n2,n3,n4,n5];
|
||||||
|
@ -278,7 +285,7 @@ fun main(){}
|
||||||
@testcase | 104 | | 1 2 3
|
@testcase | 104 | | 1 2 3
|
||||||
@testcase | 105 | | 5 5 110
|
@testcase | 105 | | 5 5 110
|
||||||
@testcase | 106 | | 160 110
|
@testcase | 106 | | 160 110
|
||||||
@testcase | 107 | | 60 70
|
@testcase | 107 | | 60 70 21 22
|
||||||
@testcase | 110 | | 320
|
@testcase | 110 | | 320
|
||||||
@testcase | 111 | | 55 55
|
@testcase | 111 | | 55 55
|
||||||
@testcase | 112 | | [ 1 13 3 23 33 ]
|
@testcase | 112 | | [ 1 13 3 23 33 ]
|
||||||
|
@ -300,7 +307,7 @@ fun main(){}
|
||||||
...
|
...
|
||||||
incrementTwoInPlace CALLDICT // x y sum1
|
incrementTwoInPlace CALLDICT // x y sum1
|
||||||
-ROT
|
-ROT
|
||||||
10 PUSHINT // sum1 x y _9=10
|
10 PUSHINT // sum1 x y _8=10
|
||||||
incrementTwoInPlace CALLDICT // sum1 x y sum2
|
incrementTwoInPlace CALLDICT // sum1 x y sum2
|
||||||
s1 s3 s0 XCHG3 // x y sum1 sum2
|
s1 s3 s0 XCHG3 // x y sum1 sum2
|
||||||
}>
|
}>
|
||||||
|
@ -310,8 +317,8 @@ fun main(){}
|
||||||
"""
|
"""
|
||||||
load_next PROC:<{
|
load_next PROC:<{
|
||||||
// cs
|
// cs
|
||||||
32 LDI // _1 cs
|
32 LDI // _3 cs
|
||||||
SWAP // cs _1
|
SWAP // cs _3
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -319,7 +326,7 @@ fun main(){}
|
||||||
"""
|
"""
|
||||||
testStoreUintPureUnusedResult PROC:<{
|
testStoreUintPureUnusedResult PROC:<{
|
||||||
//
|
//
|
||||||
0 PUSHINT // _12=0
|
0 PUSHINT // _11=0
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -330,7 +337,7 @@ fun main(){}
|
||||||
NEWC // b
|
NEWC // b
|
||||||
STIX // _2
|
STIX // _2
|
||||||
DROP //
|
DROP //
|
||||||
0 PUSHINT // _12=0
|
0 PUSHINT // _11=0
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ global `some()var`:int;
|
||||||
return `a`*-1*-(1)*---(1)*+just10()+-`just10`()*m1*-m1+-eq(m1)----0x1;
|
return `a`*-1*-(1)*---(1)*+just10()+-`just10`()*m1*-m1+-eq(m1)----0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(112) fun `bitwise~ops`(flags:int):[int,int] {
|
@method_id(112) fun `bitwise~ops`(flags:int):[bool,bool] {
|
||||||
return[
|
return[
|
||||||
(just10()-3==just10()-(4)--1)|((2==2)&(eq(eq(10)) -3==just10()--13)),
|
(just10()-3==just10()-(4)--1)|((2==2)&(eq(eq(10)) -3==just10()--13)),
|
||||||
((flags&0xFF)!=0)
|
((flags&0xFF)!=0)
|
||||||
|
|
|
@ -7,12 +7,14 @@ fun test1() {
|
||||||
numbers = listPrepend(2, numbers);
|
numbers = listPrepend(2, numbers);
|
||||||
numbers = listPrepend(3, numbers);
|
numbers = listPrepend(3, numbers);
|
||||||
numbers = listPrepend(4, numbers);
|
numbers = listPrepend(4, numbers);
|
||||||
var (h, numbers redef) = listSplit(numbers);
|
var (h: int, numbers redef) = listSplit(numbers);
|
||||||
h += listGetHead(numbers);
|
h += listGetHead(numbers);
|
||||||
|
|
||||||
|
_ = null;
|
||||||
|
(_, _) = (null, null);
|
||||||
var t = createEmptyTuple();
|
var t = createEmptyTuple();
|
||||||
do {
|
do {
|
||||||
var num = numbers.listNext();
|
var num: int = numbers.listNext();
|
||||||
t.tuplePush(num);
|
t.tuplePush(num);
|
||||||
} while (numbers != null);
|
} while (numbers != null);
|
||||||
|
|
||||||
|
@ -44,7 +46,7 @@ fun test3(x: int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUntypedNull() {
|
fun getUntypedNull() {
|
||||||
var untyped = null;
|
var untyped: null = null;
|
||||||
if (true) {
|
if (true) {
|
||||||
return untyped;
|
return untyped;
|
||||||
}
|
}
|
||||||
|
@ -52,8 +54,8 @@ fun getUntypedNull() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(104)
|
@method_id(104)
|
||||||
fun test4() {
|
fun test4(): null {
|
||||||
var (_, (_, untyped)) = (3, (createEmptyTuple, null));
|
var (_, (_, untyped: null)) = (3, (createEmptyTuple, null));
|
||||||
if (true) {
|
if (true) {
|
||||||
return untyped;
|
return untyped;
|
||||||
}
|
}
|
||||||
|
@ -62,21 +64,16 @@ fun test4() {
|
||||||
|
|
||||||
@method_id(105)
|
@method_id(105)
|
||||||
fun test5() {
|
fun test5() {
|
||||||
var n = getUntypedNull();
|
var n: slice = getUntypedNull();
|
||||||
return !(null == n) ? n.loadInt(32) : 100;
|
return !(null == n) ? n.loadInt(32) : 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(106)
|
|
||||||
fun test6(x: int) {
|
|
||||||
return x > null; // this compiles (for now), but fails at runtime
|
|
||||||
}
|
|
||||||
|
|
||||||
@method_id(107)
|
@method_id(107)
|
||||||
fun test7() {
|
fun test7() {
|
||||||
var b = beginCell().storeMaybeRef(null);
|
var b = beginCell().storeMaybeRef(null);
|
||||||
var s = b.endCell().beginParse();
|
var s = b.endCell().beginParse();
|
||||||
var c = s.loadMaybeRef();
|
var c = s.loadMaybeRef();
|
||||||
return (null == c) * 10 + (b != null);
|
return (null == c) as int * 10 + (b != null) as int;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
@ -132,27 +129,18 @@ fun main() {
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@fif_codegen
|
|
||||||
"""
|
|
||||||
test6 PROC:<{
|
|
||||||
// x
|
|
||||||
PUSHNULL // x _1
|
|
||||||
GREATER // _2
|
|
||||||
}>
|
|
||||||
"""
|
|
||||||
|
|
||||||
@fif_codegen
|
@fif_codegen
|
||||||
"""
|
"""
|
||||||
test7 PROC:<{
|
test7 PROC:<{
|
||||||
...
|
...
|
||||||
LDOPTREF // b _20 _19
|
LDOPTREF // b _18 _17
|
||||||
DROP // b c
|
DROP // b c
|
||||||
ISNULL // b _13
|
ISNULL // b _11
|
||||||
10 MULCONST // b _15
|
10 MULCONST // b _13
|
||||||
SWAP // _15 b
|
SWAP // _13 b
|
||||||
ISNULL // _15 _16
|
ISNULL // _13 _14
|
||||||
0 EQINT // _15 _17
|
NOT // _13 _15
|
||||||
ADD // _18
|
ADD // _16
|
||||||
}>
|
}>
|
||||||
"""
|
"""
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
fun justTrue(): int { return true; }
|
fun justTrue(): bool { return true; }
|
||||||
|
|
||||||
fun unary_minus_1(a: int, b: int, c: int): int{return -(a+b) *c;}
|
fun unary_minus_1(a: int, b: int, c: int): int{return -(a+b) *c;}
|
||||||
fun unary_minus_2(a: int, b: int, c: int): int{return(-(a+b))*c;}
|
fun unary_minus_2(a: int, b: int, c: int): int{return(-(a+b))*c;}
|
||||||
|
@ -6,17 +6,17 @@ fun unary_minus_3(a: int, b: int, c: int): int{return-((a+b) *c);}
|
||||||
|
|
||||||
|
|
||||||
@method_id(101)
|
@method_id(101)
|
||||||
fun test1(x: int, y: int, z: int): int {
|
fun test1(x: int, y: int, z: int): bool {
|
||||||
return (x > 0) & (y > 0) & (z > 0);
|
return (x > 0) & (y > 0) & (z > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(102)
|
@method_id(102)
|
||||||
fun test2(x: int, y: int, z: int): int {
|
fun test2(x: int, y: int, z: int): bool {
|
||||||
return x > (0 & (y > 0) & (z > 0));
|
return x > (0 & (y > 0) as int & (z > 0) as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(103)
|
@method_id(103)
|
||||||
fun test3(x: int, y: int, z: int): int {
|
fun test3(x: int, y: int, z: int): bool {
|
||||||
if ((x < 0) | (y < 0)) {
|
if ((x < 0) | (y < 0)) {
|
||||||
return z < 0;
|
return z < 0;
|
||||||
}
|
}
|
||||||
|
@ -24,29 +24,29 @@ fun test3(x: int, y: int, z: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(104)
|
@method_id(104)
|
||||||
fun test4(x: int, y: int, mode: int): int {
|
fun test4(x: int, y: int, mode: int): bool {
|
||||||
if (mode == 1) {
|
if (mode == 1) {
|
||||||
return (x == 10) | (y == 20);
|
return (x == 10) | (y == 20);
|
||||||
} if (mode == 2) {
|
} if (mode == 2) {
|
||||||
return (x == 10) | (y == 20);
|
return (x == 10) | (y == 20);
|
||||||
} else {
|
} else {
|
||||||
return x == (10 | (y == 20));
|
return x == (10 | (y == 20) as int);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(105)
|
@method_id(105)
|
||||||
fun test5(status: int): int {
|
fun test5(status: int): bool {
|
||||||
return justTrue() & (status == 1) & ((justTrue() & status) == 1);
|
return justTrue() & (status == 1) & ((justTrue() as int & status) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(106)
|
@method_id(106)
|
||||||
fun test6(a: int, b: int, c: int): int {
|
fun test6(a: int, b: int, c: int): bool {
|
||||||
return (unary_minus_1(a,b,c) == unary_minus_2(a,b,c)) & (unary_minus_1(a,b,c) == unary_minus_3(a,b,c));
|
return (unary_minus_1(a,b,c) == unary_minus_2(a,b,c)) & (unary_minus_1(a,b,c) == unary_minus_3(a,b,c));
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(107)
|
@method_id(107)
|
||||||
fun test7(b: int): int {
|
fun test7(b: int): int {
|
||||||
var a = b == 3 ? 3 : b == 4 ? 4 : (b == 5) & 1 ? 5 : 100;
|
var a = b == 3 ? 3 : b == 4 ? 4 : (b == 5) & true ? 5 : 100;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +56,14 @@ fun test8(b: int): int {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun `_<p`(a: auto, b: auto): int { return true; }
|
fun `_<p`(a: int, b: int): bool { return true; }
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
// ok to parse
|
// ok to parse
|
||||||
var c = [
|
var c = [
|
||||||
(3 & 3) > 0, 3 & (3 > 0), 3 & (`_<_`(3, 0)),
|
(3 & 3) > 0, 3 & (3 > 0) as int, 3 & (`_<_`(3, 0)),
|
||||||
3 & `_<p`(3, 0), (1 & 2) ^ (3 | 4),
|
3 & `_<p`(3, 0) as int, (1 & 2) ^ (3 | 4),
|
||||||
1 & ((1) == 1)
|
true & ((1) == 1)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ fun test1(): int {
|
||||||
@method_id(102)
|
@method_id(102)
|
||||||
fun test2(value: int): int {
|
fun test2(value: int): int {
|
||||||
save_contract_data(value);
|
save_contract_data(value);
|
||||||
var (_, restored: auto) = get_contract_data();
|
var (_, restored) = get_contract_data();
|
||||||
return restored;
|
return restored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ fun used_from_noncall2(): int { return int20; }
|
||||||
fun used_as_noncall2(): int { return 0 * 0 + used_from_noncall2() + (0 << 0); }
|
fun used_as_noncall2(): int { return 0 * 0 + used_from_noncall2() + (0 << 0); }
|
||||||
|
|
||||||
global unused_gv: int;
|
global unused_gv: int;
|
||||||
global used_gv: auto;
|
global used_gv: int;
|
||||||
|
|
||||||
fun receiveGetter(): (() -> int) { return used_as_noncall2; }
|
fun receiveGetter(): () -> int { return used_as_noncall2; }
|
||||||
|
|
||||||
@pure
|
@pure
|
||||||
fun usedButOptimizedOut(x: int): int { return x + 2; }
|
fun usedButOptimizedOut(x: int): int { return x + 2; }
|
||||||
|
|
|
@ -158,6 +158,44 @@ fun testNotMutatingChainableSelfMutateAnother(initial: int) {
|
||||||
return (arg, c108, c109, x);
|
return (arg, c108, c109, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun pickG110(mutate self: int, mutate pushTo: tuple): self {
|
||||||
|
self += 10;
|
||||||
|
pushTo.tuplePush(c110);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
global tup110: tuple;
|
||||||
|
global c110: int;
|
||||||
|
|
||||||
|
@method_id(110)
|
||||||
|
fun testMutateGlobalsLValue(init: int) {
|
||||||
|
c110 = init;
|
||||||
|
tup110 = createEmptyTuple();
|
||||||
|
c110.incChained().incChained().pickG110(mutate tup110).incChained().pickG110(mutate tup110).incChained();
|
||||||
|
return (c110, tup110);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun myTuplePush<T>(mutate self: tuple, value: T): self {
|
||||||
|
self.tuplePush(value);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun myTupleAt<T>(self: tuple, idx: int): T {
|
||||||
|
return self.tupleAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
global tup111: tuple;
|
||||||
|
|
||||||
|
@method_id(111)
|
||||||
|
fun testForallFunctionsWithSelf(): (int, int, tuple) {
|
||||||
|
var t = createEmptyTuple();
|
||||||
|
tup111 = createEmptyTuple();
|
||||||
|
t.myTuplePush(10);
|
||||||
|
tup111.myTuplePush(1).myTuplePush(2).myTuplePush(3);
|
||||||
|
return (t.myTupleAt(0), tup111.myTupleAt(tup111.tupleSize() - 1), tup111);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun main() { }
|
fun main() { }
|
||||||
|
|
||||||
|
@ -179,6 +217,8 @@ fun main() { }
|
||||||
@testcase | 109 | 200 | 200 3 1 2
|
@testcase | 109 | 200 | 200 3 1 2
|
||||||
@testcase | 109 | 100 | 100 0 0 1
|
@testcase | 109 | 100 | 100 0 0 1
|
||||||
@testcase | 109 | 102 | 102 2 1 2
|
@testcase | 109 | 102 | 102 2 1 2
|
||||||
|
@testcase | 110 | 0 | 24 [ 2 13 ]
|
||||||
|
@testcase | 111 | | 10 3 [ 1 2 3 ]
|
||||||
|
|
||||||
@fif_codegen
|
@fif_codegen
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -218,7 +218,7 @@ fun fixed248_log2_const(): int {
|
||||||
@pure
|
@pure
|
||||||
@inline
|
@inline
|
||||||
fun Pi_const_f254(): int {
|
fun Pi_const_f254(): int {
|
||||||
var (c: auto, _) = Pi_xconst_f254();
|
var (c, _) = Pi_xconst_f254();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,7 +661,7 @@ fun fixed248_pow(x: int, y: int): int {
|
||||||
return 1 << 248; // x^0 = 1
|
return 1 << 248; // x^0 = 1
|
||||||
}
|
}
|
||||||
if (x <= 0) {
|
if (x <= 0) {
|
||||||
var bad: int = (x | y) < 0;
|
var bad: int = ((x | y) < 0) as int;
|
||||||
return 0 >> bad; // 0^y = 0 if x=0 and y>=0; "out of range" exception otherwise
|
return 0 >> bad; // 0^y = 0 if x=0 and y>=0; "out of range" exception otherwise
|
||||||
}
|
}
|
||||||
var (l, s) = log2_aux_f256(x);
|
var (l, s) = log2_aux_f256(x);
|
||||||
|
@ -677,7 +677,7 @@ fun fixed248_pow(x: int, y: int): int {
|
||||||
// now log_2(x^y) = y*log_2(x) = q + ll, ss integer, ll fixed257, -1/2<=ll<1/2
|
// now log_2(x^y) = y*log_2(x) = q + ll, ss integer, ll fixed257, -1/2<=ll<1/2
|
||||||
var sq: int = q + 248;
|
var sq: int = q + 248;
|
||||||
if (sq <= 0) {
|
if (sq <= 0) {
|
||||||
return -(sq == 0); // underflow
|
return -((sq == 0) as int); // underflow
|
||||||
}
|
}
|
||||||
y = expm1_f257(mulrshiftr256(ll, log2_const_f256()));
|
y = expm1_f257(mulrshiftr256(ll, log2_const_f256()));
|
||||||
return (y ~>> (9 - q)) - (-1 << sq);
|
return (y ~>> (9 - q)) - (-1 << sq);
|
||||||
|
@ -986,7 +986,7 @@ fun tset<X>(mutate self: tuple, idx: int, value: X): void
|
||||||
// fixed256 acos_prepare_slow(fixed255 x);
|
// fixed256 acos_prepare_slow(fixed255 x);
|
||||||
@inline
|
@inline
|
||||||
fun acos_prepare_slow_f255(x: int): int {
|
fun acos_prepare_slow_f255(x: int): int {
|
||||||
x -= (x == 0);
|
x -= (x == 0) as int;
|
||||||
var t: int = 1;
|
var t: int = 1;
|
||||||
repeat (255) {
|
repeat (255) {
|
||||||
t = t * sign(x) * 2 + 1; // decode Gray code (sign(x_0), sign(x_1), ...)
|
t = t * sign(x) * 2 + 1; // decode Gray code (sign(x_0), sign(x_1), ...)
|
||||||
|
@ -1019,7 +1019,8 @@ fun test_nrand(n: int): tuple {
|
||||||
repeat (n) {
|
repeat (n) {
|
||||||
var x: int = fixed248_nrand();
|
var x: int = fixed248_nrand();
|
||||||
var bucket: int = (abs(x) >> 243); // 255 buckets starting from x=0, each 1/32 wide
|
var bucket: int = (abs(x) >> 243); // 255 buckets starting from x=0, each 1/32 wide
|
||||||
t.tset(bucket, t.tupleAt(bucket) + 1);
|
var at_bucket: int = t.tupleAt(bucket);
|
||||||
|
t.tset(bucket, at_bucket + 1);
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
fun unsafeGetInt<X>(any: X): int
|
|
||||||
asm "NOP";
|
|
||||||
|
|
||||||
@method_id(11)
|
|
||||||
fun foo(x: int): int {
|
fun foo(x: int): int {
|
||||||
try {
|
try {
|
||||||
if (x == 7) {
|
if (x == 7) {
|
||||||
|
@ -14,7 +10,6 @@ fun foo(x: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline
|
@inline
|
||||||
@method_id(12)
|
|
||||||
fun foo_inline(x: int): int {
|
fun foo_inline(x: int): int {
|
||||||
try {
|
try {
|
||||||
assert(!(x == 7)) throw 44;
|
assert(!(x == 7)) throw 44;
|
||||||
|
@ -25,36 +20,34 @@ fun foo_inline(x: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline_ref
|
@inline_ref
|
||||||
@method_id(13)
|
|
||||||
fun foo_inlineref(x: int): int {
|
fun foo_inlineref(x: int): int {
|
||||||
try {
|
try {
|
||||||
if (x == 7) { throw (44, 2); }
|
if (x == 7) { throw (44, 2); }
|
||||||
return x;
|
return x;
|
||||||
} catch (_, arg) {
|
} catch (_, arg) {
|
||||||
return unsafeGetInt(arg);
|
return arg as int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(1)
|
@method_id(101)
|
||||||
fun test(x: int, y: int, z: int): int {
|
fun test(x: int, y: int, z: int): int {
|
||||||
y = foo(y);
|
y = foo(y);
|
||||||
return x * 100 + y * 10 + z;
|
return x * 100 + y * 10 + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(2)
|
@method_id(102)
|
||||||
fun test_inline(x: int, y: int, z: int): int {
|
fun test_inline(x: int, y: int, z: int): int {
|
||||||
y = foo_inline(y);
|
y = foo_inline(y);
|
||||||
return x * 100 + y * 10 + z;
|
return x * 100 + y * 10 + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(3)
|
@method_id(103)
|
||||||
fun test_inlineref(x: int, y: int, z: int): int {
|
fun test_inlineref(x: int, y: int, z: int): int {
|
||||||
y = foo_inlineref(y);
|
y = foo_inlineref(y);
|
||||||
return x * 100 + y * 10 + z;
|
return x * 100 + y * 10 + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline
|
@inline
|
||||||
@method_id(14)
|
|
||||||
fun foo_inline_big(
|
fun foo_inline_big(
|
||||||
x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int, x8: int, x9: int, x10: int,
|
x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int, x8: int, x9: int, x10: int,
|
||||||
x11: int, x12: int, x13: int, x14: int, x15: int, x16: int, x17: int, x18: int, x19: int, x20: int
|
x11: int, x12: int, x13: int, x14: int, x15: int, x16: int, x17: int, x18: int, x19: int, x20: int
|
||||||
|
@ -69,7 +62,7 @@ fun foo_inline_big(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(4)
|
@method_id(104)
|
||||||
fun test_inline_big(x: int, y: int, z: int): int {
|
fun test_inline_big(x: int, y: int, z: int): int {
|
||||||
y = foo_inline_big(
|
y = foo_inline_big(
|
||||||
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
|
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
|
||||||
|
@ -77,7 +70,6 @@ fun test_inline_big(x: int, y: int, z: int): int {
|
||||||
return x * 1000000 + y * 1000 + z;
|
return x * 1000000 + y * 1000 + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(15)
|
|
||||||
fun foo_big(
|
fun foo_big(
|
||||||
x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int, x8: int, x9: int, x10: int,
|
x1: int, x2: int, x3: int, x4: int, x5: int, x6: int, x7: int, x8: int, x9: int, x10: int,
|
||||||
x11: int, x12: int, x13: int, x14: int, x15: int, x16: int, x17: int, x18: int, x19: int, x20: int
|
x11: int, x12: int, x13: int, x14: int, x15: int, x16: int, x17: int, x18: int, x19: int, x20: int
|
||||||
|
@ -88,11 +80,11 @@ fun foo_big(
|
||||||
}
|
}
|
||||||
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
|
return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20;
|
||||||
} catch (code, arg) {
|
} catch (code, arg) {
|
||||||
return unsafeGetInt(arg);
|
return arg as int;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(5)
|
@method_id(105)
|
||||||
fun test_big(x: int, y: int, z: int): int {
|
fun test_big(x: int, y: int, z: int): int {
|
||||||
y = foo_big(
|
y = foo_big(
|
||||||
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
|
y, y + 1, y + 2, y + 3, y + 4, y + 5, y + 6, y + 7, y + 8, y + 9,
|
||||||
|
@ -100,7 +92,7 @@ fun test_big(x: int, y: int, z: int): int {
|
||||||
return x * 1000000 + y * 1000 + z;
|
return x * 1000000 + y * 1000 + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(16)
|
@method_id(106)
|
||||||
fun test_catch_into_same(x: int): int {
|
fun test_catch_into_same(x: int): int {
|
||||||
var code = x;
|
var code = x;
|
||||||
try {
|
try {
|
||||||
|
@ -112,7 +104,7 @@ fun test_catch_into_same(x: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@method_id(17)
|
@method_id(107)
|
||||||
fun test_catch_into_same_2(x: int): int {
|
fun test_catch_into_same_2(x: int): int {
|
||||||
var code = x;
|
var code = x;
|
||||||
try {
|
try {
|
||||||
|
@ -124,28 +116,77 @@ fun test_catch_into_same_2(x: int): int {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global after046: int;
|
||||||
|
|
||||||
|
// this bug existed in FunC and is fixed in v0.4.6
|
||||||
|
fun bug_046_internal(op: int) {
|
||||||
|
if (op == 1) {
|
||||||
|
return;
|
||||||
|
} else if (op == 2) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bug_046_called() {
|
||||||
|
after046 = 0;
|
||||||
|
try {
|
||||||
|
bug_046_internal(1337);
|
||||||
|
after046 = 1; // shouldn't be called
|
||||||
|
} catch(n) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(108)
|
||||||
|
fun bug_046_entrypoint() {
|
||||||
|
bug_046_called();
|
||||||
|
return after046;
|
||||||
|
}
|
||||||
|
|
||||||
|
global g_reg: int;
|
||||||
|
|
||||||
|
@method_id(109)
|
||||||
|
fun test109(): (int, int) {
|
||||||
|
var l_reg = 10;
|
||||||
|
g_reg = 10;
|
||||||
|
try {
|
||||||
|
// note, that regardless of assignment, an exception RESTORES them to previous (to 10)
|
||||||
|
// it's very unexpected, but is considered to be a TVM feature, not a bug
|
||||||
|
g_reg = 999;
|
||||||
|
l_reg = 999;
|
||||||
|
bug_046_internal(999); // throws
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
// returns (10,10) because of an exception, see a comment above
|
||||||
|
return (g_reg, l_reg);
|
||||||
|
}
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
method_id | in | out
|
method_id | in | out
|
||||||
@testcase | 1 | 1 2 3 | 123
|
@testcase | 101 | 1 2 3 | 123
|
||||||
@testcase | 1 | 3 8 9 | 389
|
@testcase | 101 | 3 8 9 | 389
|
||||||
@testcase | 1 | 3 7 9 | 329
|
@testcase | 101 | 3 7 9 | 329
|
||||||
@testcase | 2 | 1 2 3 | 123
|
@testcase | 102 | 1 2 3 | 123
|
||||||
@testcase | 2 | 3 8 9 | 389
|
@testcase | 102 | 3 8 9 | 389
|
||||||
@testcase | 2 | 3 7 9 | 329
|
@testcase | 102 | 3 7 9 | 329
|
||||||
@testcase | 3 | 1 2 3 | 123
|
@testcase | 103 | 1 2 3 | 123
|
||||||
@testcase | 3 | 3 8 9 | 389
|
@testcase | 103 | 3 8 9 | 389
|
||||||
@testcase | 3 | 3 7 9 | 329
|
@testcase | 103 | 3 7 9 | 329
|
||||||
@testcase | 4 | 4 8 9 | 4350009
|
@testcase | 104 | 4 8 9 | 4350009
|
||||||
@testcase | 4 | 4 7 9 | 4001009
|
@testcase | 104 | 4 7 9 | 4001009
|
||||||
@testcase | 5 | 4 8 9 | 4350009
|
@testcase | 105 | 4 8 9 | 4350009
|
||||||
@testcase | 5 | 4 7 9 | 4001009
|
@testcase | 105 | 4 7 9 | 4001009
|
||||||
@testcase | 16 | 5 | 5
|
@testcase | 106 | 5 | 5
|
||||||
@testcase | 16 | 20 | 44
|
@testcase | 106 | 20 | 44
|
||||||
@testcase | 17 | 5 | 5
|
@testcase | 107 | 5 | 5
|
||||||
@testcase | 17 | 20 | 20
|
@testcase | 107 | 20 | 20
|
||||||
|
@testcase | 108 | | 0
|
||||||
|
|
||||||
@code_hash 73240939343624734070640372352271282883450660826541545137654364443860257436623
|
@code_hash 39307974281105539319288356721945232226028429128341177951717392648324358675585
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -38,7 +38,7 @@ fun foo_until(x: int): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(4)
|
@method_id(4)
|
||||||
fun test4(x: int): (int, int) {
|
fun test4(x: int): (int, bool) {
|
||||||
var s = 0;
|
var s = 0;
|
||||||
var reached = false;
|
var reached = false;
|
||||||
do {
|
do {
|
||||||
|
|
14
tolk-tester/tests/unreachable-1.tolk
Normal file
14
tolk-tester/tests/unreachable-1.tolk
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
fun main(x: int) {
|
||||||
|
if (x) {
|
||||||
|
x = 10;;;;;
|
||||||
|
return x;;;
|
||||||
|
x = 20;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@testcase | 0 | 1 | 10
|
||||||
|
@stderr warning: unreachable code
|
||||||
|
@stderr x = 20;
|
||||||
|
*/
|
22
tolk-tester/tests/unreachable-2.tolk
Normal file
22
tolk-tester/tests/unreachable-2.tolk
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
fun main(x: int) {
|
||||||
|
if (x) {
|
||||||
|
if (x > 10) {
|
||||||
|
return 1; // throw 1;
|
||||||
|
} else if (true) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 2; // throw 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
{{return 1;}
|
||||||
|
x = 30;}
|
||||||
|
}
|
||||||
|
assert(false, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@testcase | 0 | 1 | -1
|
||||||
|
@stderr warning: unreachable code
|
||||||
|
@stderr assert(false, 10)
|
||||||
|
@stderr x = 30
|
||||||
|
*/
|
|
@ -15,8 +15,127 @@ fun testVarApply1() {
|
||||||
return (s.loadInt(32), s.loadInt(32));
|
return (s.loadInt(32), s.loadInt(32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@inline
|
||||||
|
fun my_throw_always() {
|
||||||
|
throw 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline
|
||||||
|
fun get_raiser() {
|
||||||
|
return my_throw_always;
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(102)
|
||||||
|
fun testVarApplyWithoutSavingResult() {
|
||||||
|
try {
|
||||||
|
var raiser = get_raiser();
|
||||||
|
raiser(); // `some_var()` is always impure, the compiler has no considerations about its runtime value
|
||||||
|
return 0;
|
||||||
|
} catch (code) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline
|
||||||
|
fun sum(a: int, b: int) {
|
||||||
|
assert(a + b < 24, 1000);
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline
|
||||||
|
fun mul(a: int, b: int) {
|
||||||
|
assert(a * b < 24, 1001);
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun demo_handler(op: int, query_id: int, a: int, b: int): int {
|
||||||
|
if (op == 0xF2) {
|
||||||
|
val func = query_id % 2 == 0 ? sum : mul;
|
||||||
|
val result = func(a, b);
|
||||||
|
return 0; // result not used, we test that func is nevertheless called
|
||||||
|
}
|
||||||
|
if (op == 0xF4) {
|
||||||
|
val func = query_id % 2 == 0 ? sum : mul;
|
||||||
|
val result = func(a, b);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(103)
|
||||||
|
fun testVarApplyInTernary() {
|
||||||
|
var t: tuple = createEmptyTuple();
|
||||||
|
try {
|
||||||
|
t.tuplePush(demo_handler(0xF2, 122, 100, 200));
|
||||||
|
} catch(code) {
|
||||||
|
t.tuplePush(code);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
t.tuplePush(demo_handler(0xF4, 122, 100, 200));
|
||||||
|
} catch(code) {
|
||||||
|
t.tuplePush(code);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
t.tuplePush(demo_handler(0xF2, 122, 10, 10));
|
||||||
|
} catch(code) {
|
||||||
|
t.tuplePush(code);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
t.tuplePush(demo_handler(0xF2, 123, 10, 10));
|
||||||
|
} catch(code) {
|
||||||
|
t.tuplePush(code);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun always_throw2(x: int) {
|
||||||
|
throw 239 + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
global global_f: int -> void;
|
||||||
|
|
||||||
|
@method_id(104)
|
||||||
|
fun testGlobalVarApply() {
|
||||||
|
try {
|
||||||
|
global_f = always_throw2;
|
||||||
|
global_f(1);
|
||||||
|
return 0;
|
||||||
|
} catch (code) {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(105)
|
||||||
|
fun testVarApply2() {
|
||||||
|
var creator = createEmptyTuple;
|
||||||
|
var t = creator();
|
||||||
|
t.tuplePush(1);
|
||||||
|
var sizer = t.tupleSize;
|
||||||
|
return sizer(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTupleLastGetter<X>(): (tuple) -> X {
|
||||||
|
return tupleLast<X>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@method_id(106)
|
||||||
|
fun testVarApply3() {
|
||||||
|
var t = createEmptyTuple();
|
||||||
|
t.tuplePush(1);
|
||||||
|
t.tuplePush([2]);
|
||||||
|
var getIntAt = t.tupleAt<int>;
|
||||||
|
var getTupleFirstInt = createEmptyTuple().tupleFirst<int>;
|
||||||
|
var getTupleLastTuple = getTupleLastGetter<tuple>();
|
||||||
|
return (getIntAt(t, 0), getTupleFirstInt(t), getTupleLastTuple(t), getTupleLastGetter<tuple>()(t));
|
||||||
|
}
|
||||||
|
|
||||||
fun main() {}
|
fun main() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@testcase | 101 | | 1 2
|
@testcase | 101 | | 1 2
|
||||||
|
@testcase | 102 | | 1000
|
||||||
|
@testcase | 103 | | [ 1000 1000 0 1001 ]
|
||||||
|
@testcase | 104 | | 240
|
||||||
|
@testcase | 105 | | 1
|
||||||
|
@testcase | 106 | | 1 1 [ 2 ] [ 2 ]
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,7 +6,7 @@ fun main(x: int): int {
|
||||||
if (i > 5) {
|
if (i > 5) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
var f: int = (i * i == 64);
|
var f: bool = (i * i == 64);
|
||||||
} while (!f);
|
} while (!f);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ fun test(y: int): int {
|
||||||
if (y > 0) {
|
if (y > 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return x > 0;
|
return x > 0 ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@method_id(2)
|
@method_id(2)
|
||||||
|
|
|
@ -347,11 +347,11 @@ class TolkTestFile {
|
||||||
if (exit_code === 0 && this.compilation_should_fail)
|
if (exit_code === 0 && this.compilation_should_fail)
|
||||||
throw new TolkCompilationSucceededError("compilation succeeded, but it should have failed")
|
throw new TolkCompilationSucceededError("compilation succeeded, but it should have failed")
|
||||||
|
|
||||||
if (exit_code !== 0 && this.compilation_should_fail) {
|
for (let should_include of this.stderr_includes) // @stderr is used to check errors and warnings
|
||||||
for (let should_include of this.stderr_includes)
|
should_include.check(stderr)
|
||||||
should_include.check(stderr)
|
|
||||||
|
if (exit_code !== 0 && this.compilation_should_fail)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
if (exit_code !== 0 && !this.compilation_should_fail)
|
if (exit_code !== 0 && !this.compilation_should_fail)
|
||||||
throw new TolkCompilationFailedError(`tolk exit_code = ${exit_code}`, stderr)
|
throw new TolkCompilationFailedError(`tolk exit_code = ${exit_code}`, stderr)
|
||||||
|
|
|
@ -327,9 +327,10 @@ class TolkTestFile:
|
||||||
if exit_code == 0 and self.compilation_should_fail:
|
if exit_code == 0 and self.compilation_should_fail:
|
||||||
raise TolkCompilationSucceededError("compilation succeeded, but it should have failed")
|
raise TolkCompilationSucceededError("compilation succeeded, but it should have failed")
|
||||||
|
|
||||||
|
for should_include in self.stderr_includes: # @stderr is used to check errors and warnings
|
||||||
|
should_include.check(stderr)
|
||||||
|
|
||||||
if exit_code != 0 and self.compilation_should_fail:
|
if exit_code != 0 and self.compilation_should_fail:
|
||||||
for should_include in self.stderr_includes:
|
|
||||||
should_include.check(stderr)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if exit_code != 0 and not self.compilation_should_fail:
|
if exit_code != 0 and not self.compilation_should_fail:
|
||||||
|
|
|
@ -7,14 +7,24 @@ set(TOLK_SOURCE
|
||||||
compiler-state.cpp
|
compiler-state.cpp
|
||||||
ast.cpp
|
ast.cpp
|
||||||
ast-from-tokens.cpp
|
ast-from-tokens.cpp
|
||||||
|
constant-evaluator.cpp
|
||||||
pipe-discover-parse-sources.cpp
|
pipe-discover-parse-sources.cpp
|
||||||
pipe-register-symbols.cpp
|
pipe-register-symbols.cpp
|
||||||
|
pipe-resolve-identifiers.cpp
|
||||||
|
pipe-calc-rvalue-lvalue.cpp
|
||||||
|
pipe-detect-unreachable.cpp
|
||||||
|
pipe-infer-types-and-calls.cpp
|
||||||
|
pipe-refine-lvalue-for-mutate.cpp
|
||||||
|
pipe-check-rvalue-lvalue.cpp
|
||||||
|
pipe-check-pure-impure.cpp
|
||||||
|
pipe-constant-folding.cpp
|
||||||
|
pipe-optimize-boolean-expr.cpp
|
||||||
pipe-ast-to-legacy.cpp
|
pipe-ast-to-legacy.cpp
|
||||||
pipe-find-unused-symbols.cpp
|
pipe-find-unused-symbols.cpp
|
||||||
pipe-generate-fif-output.cpp
|
pipe-generate-fif-output.cpp
|
||||||
unify-types.cpp
|
type-system.cpp
|
||||||
|
generics-helpers.cpp
|
||||||
abscode.cpp
|
abscode.cpp
|
||||||
gen-abscode.cpp
|
|
||||||
analyzer.cpp
|
analyzer.cpp
|
||||||
asmops.cpp
|
asmops.cpp
|
||||||
builtins.cpp
|
builtins.cpp
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue