{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Welcome to the FunC interactive cheat sheet!\n", "This tutorial is still in work, any contribution is highly appreciated! \n", "Language basics will be covered, more information can be found in the TON repo:\n", "1. [TVM docs](https://test.ton.org/tvm.pdf)\n", "2. [Tests](https://github.com/ton-blockchain/ton/tree/9c9248a9ae1791152d88c9c36574b4becdf5e8b6/crypto/func/test)\n", "3. [Sample contracts](https://github.com/ton-blockchain/ton/tree/9c9248a9ae1791152d88c9c36574b4becdf5e8b6/crypto/smartcont)\n", "\n", "Basically, FunC is quite lightweight abstraction on top of TVM assembler, so if you read TVM spec you will likely get the core concepts very quickly.\n", "\n", "## Contents\n", "* [Xeus-Fift specific features](#🍬-Xeus-Fift-specific-features)\n", " * [Include macro](#Include-macro)\n", " * [Main-wrapper](#Main-wrapper)\n", " * [Force return](#Force-return)\n", "* [Integers](#Integers)\n", " * [Basic operations](#Basic-operations)\n", " * [Division rounding rules](#Division-rounding-rules)\n", " * [Compound operators](#Compound-operators)\n", " * [Constants](#Constants)\n", "* [Tuples](#Tuples)\n", " * [FunC tuples](#FunC-tuples)\n", " * [TVM tuples](#TVM-tuples)\n", " * [Pairs](#Pairs)\n", " * [Triples](#Triples)\n", " * [4-tuples](#4-tuples)\n", " * [Lists](#Lists)\n", "* [Cells](#Cells)\n", " * [Builders](#Builders)\n", " * [Slices](#Slices)\n", " * [Hashmaps](#Hashmaps)\n", "* [Functions](#Functions)\n", " * [ASM bindings](#ASM-bindings)\n", " * [Generics](#Generics)\n", "* [Conditional statements](#Conditional-statements)\n", " * [Ternary operator](#Ternary-operator)\n", "* [Loops](#Loops)\n", "* [Exceptions](#Exceptions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 🍬 Xeus-Fift specific features\n", "### Include macro" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
"
      ],
      "text/plain": []
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#include \"stdlib.fc\"  ;; searches for file in the FUNCPATH and workdir"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Main-wrapper\n",
    "There can be three types of cell:\n",
    "1. Includes\n",
    "2. Function definitions (these functions can be accessed from all other cells)\n",
    "3. Non-wrapped code\n",
    "\n",
    "This non-wrapped code is taken as `main` entrypoint source and cannot be accessed from other cells.  \n",
    "Consider running a cell as a single invocation of a contract."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Force return\n",
    "In order to provide a truly interactive experience, xeus-fift inspects the last line of the cell and adds `return`  and trailing semicolon if needed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Integers\n",
    "### Basic operations\n",
    "Underlying TVM type: signed 257-bit integers, representing integer numbers in the\n",
    "range -2^256 ... 2^256 − 1\n",
    "\n",
    "* Arithmetic `+`  `-`  `*`  `/`  `%`   \n",
    "* Bitwise `&`  `|`  `<<`  `>>`   \n",
    "* Boolean `<`  `<=`  `>`  `>=`  `==`  `!=` "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
129
" ], "text/plain": [ "129" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "0x01 ^ 0x80 ;; xor" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1
" ], "text/plain": [ "1" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "8 <=> -4 ;; compare (1 if equal, -1 if less, 0 otherwise)" ] }, { "cell_type": "code", "execution_count": 210, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-1
" ], "text/plain": [ "-1" ] }, "execution_count": 210, "metadata": {}, "output_type": "execute_result" } ], "source": [ "~ 0xff + 0xff ;; bitwise complement" ] }, { "cell_type": "code", "execution_count": 214, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-2
" ], "text/plain": [ "-2" ] }, "execution_count": 214, "metadata": {}, "output_type": "execute_result" } ], "source": [ "min(-2, 0)" ] }, { "cell_type": "code", "execution_count": 216, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
3
" ], "text/plain": [ "3" ] }, "execution_count": 216, "metadata": {}, "output_type": "execute_result" } ], "source": [ "max(2, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Division rounding rules" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
2
" ], "text/plain": [ "2" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "9 ~>> 2 ;; division by 2^n using nearest-integer rounding" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
3
" ], "text/plain": [ "3" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "9 ^>> 2 ;; division by 2^n using ceiling rounding" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rounding works similarly for integer division and modular division operators: \n", "`~/` `^/` `~%` `^%`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Compound operators" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
5 1
" ], "text/plain": [ "5 1" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "11 /% 2 ;; extended mod division: computes both the quotient and the remainder" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
5 1
" ], "text/plain": [ "5 1" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "divmod(11, 2) ;; same effect" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1 5
" ], "text/plain": [ "1 5" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "moddiv(11, 2) ;; change output order" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
5 1
" ], "text/plain": [ "5 1" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int x = 11; ;; declaring variable of type `int`\n", "x~divmod(2) ;; non-const method (starting with `~`)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
44
" ], "text/plain": [ "44" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int x = 42;\n", "x += 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similar let-constructions can be made on top of with practically all integer operators: \n", "`-=` `*=` `/=` `%=` \n", "`&=` `|=` `<<=` `>>=` `^=` \n", "`~>>=` `^>>=` `~/=` `^/=` `~%=` `^%=`" ] }, { "cell_type": "code", "execution_count": 104, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
4
" ], "text/plain": [ "4" ] }, "execution_count": 104, "metadata": {}, "output_type": "execute_result" } ], "source": [ "muldiv(3, 3, 2) ;; equivalent of `a * b / c`" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
5
" ], "text/plain": [ "5" ] }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ "muldivr(3, 3, 2) ;; equivalent of `a * b ~/ c`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Constants" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-1
" ], "text/plain": [ "-1" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "true" ] }, { "cell_type": "code", "execution_count": 191, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
0
" ], "text/plain": [ "0" ] }, "execution_count": 191, "metadata": {}, "output_type": "execute_result" } ], "source": [ "false" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-1
" ], "text/plain": [ "-1" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "~ false \n", " \n", "{-\n", " Btw, this is a multiline comment\n", "-}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tuples\n", "### FunC tuples" ] }, { "cell_type": "code", "execution_count": 194, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1 2 3
" ], "text/plain": [ "1 2 3" ] }, "execution_count": 194, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var t = (1, 2, 3); ;; packing\n", "t" ] }, { "cell_type": "code", "execution_count": 174, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
2
" ], "text/plain": [ "2" ] }, "execution_count": 174, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var (a, b, c) = (1, 2, 3); ;; unpacking\n", "b" ] }, { "cell_type": "code", "execution_count": 175, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
2 3
" ], "text/plain": [ "2 3" ] }, "execution_count": 175, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var (a, b) = (1, (2, 3));\n", "b" ] }, { "cell_type": "code", "execution_count": 234, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
205
" ], "text/plain": [ "205" ] }, "execution_count": 234, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var (_, x, _) = (0xab, 0xcd, 0xef); ;; one can use special operand `_` for values that won't be used\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### TVM tuples\n", "An ordered collection of up to 255 components, having arbitrary value types, possibly distinct. \n", "May be used to represent nonpersistent values of arbitrary algebraic data types." ] }, { "cell_type": "code", "execution_count": 176, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[]
" ], "text/plain": [ "[]" ] }, "execution_count": 176, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Nil ;; 0-tuple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Pairs" ] }, { "cell_type": "code", "execution_count": 177, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[ 57005 48815 ]
" ], "text/plain": [ "[ 57005 48815 ]" ] }, "execution_count": 177, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pair(0xdead, 0xbeaf)" ] }, { "cell_type": "code", "execution_count": 208, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
48815
" ], "text/plain": [ "48815" ] }, "execution_count": 208, "metadata": {}, "output_type": "execute_result" } ], "source": [ "second(pair(0xdead, 0xbeaf))" ] }, { "cell_type": "code", "execution_count": 217, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
57005
" ], "text/plain": [ "57005" ] }, "execution_count": 217, "metadata": {}, "output_type": "execute_result" } ], "source": [ "at(pair(0xdead, 0xbeaf), 0) ;; universal helper for tuples" ] }, { "cell_type": "code", "execution_count": 179, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
57005 48815
" ], "text/plain": [ "57005 48815" ] }, "execution_count": 179, "metadata": {}, "output_type": "execute_result" } ], "source": [ "unpair(pair(0xdead, 0xbeaf))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Triples" ] }, { "cell_type": "code", "execution_count": 180, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[ 1 2 3 ]
" ], "text/plain": [ "[ 1 2 3 ]" ] }, "execution_count": 180, "metadata": {}, "output_type": "execute_result" } ], "source": [ "triple(1, 2, 3)" ] }, { "cell_type": "code", "execution_count": 202, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
3
" ], "text/plain": [ "3" ] }, "execution_count": 202, "metadata": {}, "output_type": "execute_result" } ], "source": [ "third(triple(1, 2, 3))" ] }, { "cell_type": "code", "execution_count": 182, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1 2 3
" ], "text/plain": [ "1 2 3" ] }, "execution_count": 182, "metadata": {}, "output_type": "execute_result" } ], "source": [ "untriple(triple(1, 2, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 4-tuples" ] }, { "cell_type": "code", "execution_count": 183, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[ -10 -20 -30 -40 ]
" ], "text/plain": [ "[ -10 -20 -30 -40 ]" ] }, "execution_count": 183, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tuple4(-10, -20, -30, -40)" ] }, { "cell_type": "code", "execution_count": 184, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-40
" ], "text/plain": [ "-40" ] }, "execution_count": 184, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fourth(tuple4(-10, -20, -30, -40))" ] }, { "cell_type": "code", "execution_count": 185, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-10 -20 -30 -40
" ], "text/plain": [ "-10 -20 -30 -40" ] }, "execution_count": 185, "metadata": {}, "output_type": "execute_result" } ], "source": [ "untuple4(tuple4(-10, -20, -30, -40))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Lists" ] }, { "cell_type": "code", "execution_count": 186, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[ 1 [ 2 [ 3 [] ] ] ]
" ], "text/plain": [ "[ 1 [ 2 [ 3 [] ] ] ]" ] }, "execution_count": 186, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cons(1, cons(2, cons(3, Nil)))" ] }, { "cell_type": "code", "execution_count": 187, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1 [ 2 [ 3 [] ] ]
" ], "text/plain": [ "1 [ 2 [ 3 [] ] ]" ] }, "execution_count": 187, "metadata": {}, "output_type": "execute_result" } ], "source": [ "uncons(cons(1, cons(2, cons(3, Nil)))) ;; (head, tail)" ] }, { "cell_type": "code", "execution_count": 188, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1
" ], "text/plain": [ "1" ] }, "execution_count": 188, "metadata": {}, "output_type": "execute_result" } ], "source": [ "car(cons(1, cons(2, cons(3, Nil)))) ;; head" ] }, { "cell_type": "code", "execution_count": 189, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[ 2 [ 3 [] ] ]
" ], "text/plain": [ "[ 2 [ 3 [] ] ]" ] }, "execution_count": 189, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cdr(cons(1, cons(2, cons(3, Nil)))) ;; tail" ] }, { "cell_type": "code", "execution_count": 190, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
[ 2 [ 3 [] ] ] 1
" ], "text/plain": [ "[ 2 [ 3 [] ] ] 1" ] }, "execution_count": 190, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list_next(cons(1, cons(2, cons(3, Nil)))); ;; (tail, head)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cells\n", "A TVM cell consists of at most 1023 bits of data, and of at\n", "most four references to other cells. \n", "All persistent data (including TVM\n", "code) in the TON Blockchain is represented as a collection of TVM\n", "cells. \n", "\n", "The cell primitives are mostly either cell serialization primitives, which work\n", "with Builder s, or cell deserialization primitives, which work with Slices." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Builders\n", "A TVM cell builder, or builder for short, is an “incomplete”\n", "cell that supports fast operations of appending bitstrings and cell references at its end. \n", "Builders are used for packing (or serializing) data\n", "from the top of the stack into new cells (e.g., before transferring them\n", "to persistent storage)." ] }, { "cell_type": "code", "execution_count": 255, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
BC{0000}
" ], "text/plain": [ "BC{0000}" ] }, "execution_count": 255, "metadata": {}, "output_type": "execute_result" } ], "source": [ "builder b = begin_cell() ;; two descriptor bytes come first (read more in 3.1.4. Standard cell representation)" ] }, { "cell_type": "code", "execution_count": 246, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
C{96A296D224F285C67BEE93C30F8A309157F0DAA35DC5B87E410B78630A09CFC7}
" ], "text/plain": [ "C{96A296D224F285C67BEE93C30F8A309157F0DAA35DC5B87E410B78630A09CFC7}" ] }, "execution_count": 246, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cell res = end_cell(begin_cell());" ] }, { "cell_type": "code", "execution_count": 302, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
C{96A296D224F285C67BEE93C30F8A309157F0DAA35DC5B87E410B78630A09CFC7}
" ], "text/plain": [ "C{96A296D224F285C67BEE93C30F8A309157F0DAA35DC5B87E410B78630A09CFC7}" ] }, "execution_count": 302, "metadata": {}, "output_type": "execute_result" } ], "source": [ "begin_cell().end_cell() ;; const method (dot is not a part of the function name)" ] }, { "cell_type": "code", "execution_count": 281, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
BC{0008ffffff01}
" ], "text/plain": [ "BC{0008ffffff01}" ] }, "execution_count": 281, "metadata": {}, "output_type": "execute_result" } ], "source": [ "begin_cell().store_int(-0xFF, 32) ;; we added a 32bit signed integer" ] }, { "cell_type": "code", "execution_count": 283, "metadata": {}, "outputs": [ { "ename": "VM error", "evalue": "integer out of range", "output_type": "error", "traceback": [ "VM error: integer out of range" ] } ], "source": [ "begin_cell().store_uint(-42, 32)" ] }, { "cell_type": "code", "execution_count": 284, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
BC{0100}
" ], "text/plain": [ "BC{0100}" ] }, "execution_count": 284, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cell c1 = begin_cell().store_int(1, 8).end_cell();\n", "begin_cell().store_ref(c1) ;; first byte indicates that cell holds one reference" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Slices\n", "A TVM cell slice, or slice for short, is a contiguous “sub-cell”\n", "of an existing cell, containing some of its bits of data and some of its\n", "references. \n", "Essentially, a slice is a read-only view for a subcell of a cell. \n", "Slices are used for unpacking data previously stored (or serialized) in a\n", "cell or a tree of cells." ] }, { "cell_type": "code", "execution_count": 307, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
CS{Cell{000400fa} bits: 0..16; refs: 0..0}
" ], "text/plain": [ "CS{Cell{000400fa} bits: 0..16; refs: 0..0}" ] }, "execution_count": 307, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cell c = begin_cell().store_int(0xfa, 16).end_cell();\n", "c.begin_parse()" ] }, { "cell_type": "code", "execution_count": 315, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
250
" ], "text/plain": [ "250" ] }, "execution_count": 315, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cell c = begin_cell().store_int(0xfa, 16).end_cell();\n", "slice cs = c.begin_parse();\n", "int res = cs~load_int(16);\n", "res" ] }, { "cell_type": "code", "execution_count": 334, "metadata": {}, "outputs": [ { "ename": "VM error", "evalue": "cell underflow", "output_type": "error", "traceback": [ "VM error: cell underflow" ] } ], "source": [ "cell c = begin_cell().store_uint(0xfa, 16).end_cell();\n", "slice cs = c.begin_parse();\n", "var (b1, b2) = (cs~load_uint(16), cs~load_uint(16)) ;; non-const method `load` reads and increases offset" ] }, { "cell_type": "code", "execution_count": 430, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
"
      ],
      "text/plain": []
     },
     "execution_count": 430,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cell c = begin_cell().store_int(0xfa, 16).end_cell();\n",
    "slice cs = c.begin_parse();\n",
    "cs.skip_bits(16).end_parse()  ;; ensure we read the entire cell with `end_parse`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 397,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
250
" ], "text/plain": [ "250" ] }, "execution_count": 397, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cell c = begin_cell().store_int(0xfa, 9).end_cell();\n", "slice cs = c.begin_parse();\n", "slice c8 = cs.skip_bits(1).first_bits(8);\n", "c8.preload_uint(8) ;; read without increasing the offset" ] }, { "cell_type": "code", "execution_count": 416, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1
" ], "text/plain": [ "1" ] }, "execution_count": 416, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cell c1 = begin_cell().store_uint(1, 1).end_cell();\n", "cell c2 = begin_cell().store_ref(c1).end_cell();\n", "cell c3 = c2.begin_parse().preload_ref();\n", "c3.begin_parse().preload_uint(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Hashmaps\n", "Hashmaps, or dictionaries, are a specific data structure represented by a tree\n", "of cells." ] }, { "cell_type": "code", "execution_count": 294, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
(null)
" ], "text/plain": [ "(null)" ] }, "execution_count": 294, "metadata": {}, "output_type": "execute_result" } ], "source": [ "new_dict()" ] }, { "cell_type": "code", "execution_count": 295, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
-1
" ], "text/plain": [ "-1" ] }, "execution_count": 295, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dict_empty?(new_dict())" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
"
      ],
      "text/plain": []
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "slice test_slice(int byte) {\n",
    "    cell c = begin_cell().store_uint(byte, 8).end_cell();\n",
    "    return c.begin_parse();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Set value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
CS{Cell{0005a007ea} bits: 0..22; refs: 0..0}
" ], "text/plain": [ "CS{Cell{0005a007ea} bits: 0..22; refs: 0..0}" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var d = new_dict();\n", "d~udict_set(8, 1, test_slice(0xfa));\n", "d.begin_parse()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Replace only if exists" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
CS{Cell{0005a007ee} bits: 0..22; refs: 0..0}
" ], "text/plain": [ "CS{Cell{0005a007ee} bits: 0..22; refs: 0..0}" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var d = new_dict();\n", "d~udict_set(8, 1, test_slice(0xfa));\n", "var (d1, _) = udict_replace?(d, 8, 1, test_slice(0xfb));\n", "d1.begin_parse()" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
0
" ], "text/plain": [ "0" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var d = new_dict();\n", "var (d1, found) = udict_replace?(d, 8, 1, test_slice(0xfa));\n", "found" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Delete key" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
(null) -1
" ], "text/plain": [ "(null) -1" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var d = new_dict();\n", "d~udict_set(8, 1, test_slice(0xfa));\n", "udict_delete?(d, 8, 1) ;; returns new dict and boolean flag (found or not)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Get value" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
CS{Cell{0005a007ea} bits: 14..22; refs: 0..0} -1
" ], "text/plain": [ "CS{Cell{0005a007ea} bits: 14..22; refs: 0..0} -1" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "var d = new_dict();\n", "d~udict_set(8, 1, test_slice(0xfa));\n", "udict_get?(d, 8, 1) ;; returns slice and boolean flag (found or not)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Functions\n", "#### Return type\n", "Can be any combination (nested funC tuples) of builtin types `int` `tuple` `cell` `slice` `builder` `cont`, special \"hole\" type `_` (type is deduced from the return value), or void (empty tuple) `()`\n", "\n", "#### Modifiers\n", "* `impure` - tells the compiler that function can modify passed arguments, and prevents function invocation pruning during the optimization;\n", "* `inline` - works pretty the same as in C, tells the compiler to paste function body on every call occurence;\n", "* `inline_ref` - in case of a simple inlining, an n-bit slice of the current continuation (cell) is converted to a new continuation (code and codepage), while inline_ref is when a cell reference is converted to a continuation and pushed onto the stack (more info in 4.2.3. Constant, or literal, continuations);\n", "* `method_id` - declares a Get method (entrypoint) for the contract (that can be called along with the `main`, `recv_internal` and `recv_external`)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ASM bindings\n", "`asm` ( `stack order of arguments` -> `stack order of return values` ) \"`INSTRUCTION#0`\" \"`INSTRUCTION#1`\" ... \"`INSTRUCTION#N`\"\n", "Here is a comprehensive sample function from stdlib demonstrating all possible outcomes:" ] }, { "cell_type": "code", "execution_count": 426, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
"
      ],
      "text/plain": []
     },
     "execution_count": 426,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTUGETNEXT\" \"NULLSWAPIFNOT\" \"NULLSWAPIFNOT\";"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One can omit both or separate args/return stack ordering:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 427,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
"
      ],
      "text/plain": []
     },
     "execution_count": 427,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "int dict_empty?(cell c) asm \"DICTEMPTY\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 428,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
"
      ],
      "text/plain": []
     },
     "execution_count": 428,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(slice, cell) load_ref(slice s) asm( -> 1 0) \"LDREF\";"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 429,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
"
      ],
      "text/plain": []
     },
     "execution_count": 429,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTISETREF\";"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Generics\n",
    "`forall` `X0`, `X1`, ... , `Xn` -> "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 425,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
"
      ],
      "text/plain": []
     },
     "execution_count": 425,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "forall X, Y -> tuple pair(X x, Y y) asm \"PAIR\";"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conditional statements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "
1
" ], "text/plain": [ "1" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "if (true) {\n", " print(1);\n", "} else {\n", " print(2);\n", "}" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
5
" ], "text/plain": [ "5" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ifnot (true) {\n", " print(3);\n", "} elseif (false) {\n", " print(4);\n", "} elseifnot (false) {\n", " print(5);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ternary operator" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1
" ], "text/plain": [ "1" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "return 0 == 0 ? 1 : 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loops" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
10 9 8 7 6 5 4 3 2 1
" ], "text/plain": [ "10 9 8 7 6 5 4 3 2 1" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int i = 10;\n", "while (i > 0) {\n", " print(i);\n", " i -= 1;\n", "}" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
10 9 8 7 6 5 4 3 2 1
" ], "text/plain": [ "10 9 8 7 6 5 4 3 2 1" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int i = 10;\n", "do {\n", " print(i);\n", " i -= 1;\n", "} until (i == 0)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
1000000
" ], "text/plain": [ "1000000" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int i = 10;\n", "repeat (5) { i *= 10; }\n", "i" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exceptions" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "ename": "VM error", "evalue": "unknown code 31", "output_type": "error", "traceback": [ "VM error: unknown code 31" ] } ], "source": [ "throw(31)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "ename": "VM error", "evalue": "unknown code 32", "output_type": "error", "traceback": [ "VM error: unknown code 32" ] } ], "source": [ "throw_if(32, true);" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "ename": "VM error", "evalue": "unknown code 33", "output_type": "error", "traceback": [ "VM error: unknown code 33" ] } ], "source": [ "throw_unless(33, false)" ] } ], "metadata": { "kernelspec": { "display_name": "FunC", "language": "FunC", "name": "func" }, "language_info": { "codemirror_mode": "func", "file_extension": ".fc", "mimetype": "text/x-func", "name": "func", "version": "0.5" } }, "nbformat": 4, "nbformat_minor": 2 }