diff --git a/pages/book/_meta.js b/pages/book/_meta.js index 384fa907..41ad513a 100644 --- a/pages/book/_meta.js +++ b/pages/book/_meta.js @@ -10,6 +10,7 @@ export default { types: 'Type system overview', integers: 'Integers', operators: 'Operators', + expressions: 'Expressions', statements: 'Statements', constants: 'Constants', functions: 'Functions', diff --git a/pages/book/composite-types.mdx b/pages/book/composite-types.mdx index e898eaeb..4300b610 100644 --- a/pages/book/composite-types.mdx +++ b/pages/book/composite-types.mdx @@ -4,7 +4,7 @@ import { Callout } from 'nextra/components' Tact supports a number of [primitive data types](/book/types#primitive-types) that are tailored for smart contract use. However, using individual means of storage often becomes cumbersome, so there are two main ways to combine multiple primitives together: [Structs](#structs) and [Messages](#messages). -Note, while Traits and Contracts are also considered a part of the Tacts type system, one can't pass them around like [Structs](#structs) or [Messages](#messages). Instead, one can obtain the initial state of the given Contract by using the [initOf](/book/statements#initof) statement described later in the Book. +Note, while Traits and Contracts are also considered a part of the Tacts type system, one can't pass them around like [Structs](#structs) or [Messages](#messages). Instead, one can obtain the initial state of the given Contract by using the [`initOf{:tact}`](/book/expressions#initof) expression. diff --git a/pages/book/expressions.mdx b/pages/book/expressions.mdx new file mode 100644 index 00000000..07c79fb0 --- /dev/null +++ b/pages/book/expressions.mdx @@ -0,0 +1,193 @@ +# Expressions + +import { Callout } from 'nextra/components' + +Every operator in Tact forms an expression, but there's much more to uncover as Tact offers a wide range of expressive options to choose from. + +## Literals + +Literals represent values in Tact. These are fixed values—not variables—that you _literally_ provide in your code. All literals in Tact are expressions themselves. + +You can also call [extension functions](/book/functions#extension-function) defined on certain [primitive types][p] corresponding to literals right on the literal values: + +```tact +// Calling toString() defined for Int on a integer literal: +42.toString(); + +// Calling asComment() defined for String on a string literal: +"Tact is awesome!".asComment(); +``` + +### Integer literals + +Integer literals can be written in [decimal](/book/integers#decimal) (base $10$), [hexadecimal](/book/integers#hexadecimal) (base $16$), [octal](/book/integers#octal) (base $8$) and [binary](/book/integers#binary) (base $2$) notations: + +* A [_decimal_ integer](/book/integers#decimal) literal is a sequence of digits ($\mathrm{0 - 9}$). + +* A leading $\mathrm{0x}$ (or $\mathrm{0X}$) indicates a [hexadecimal integer](/book/integers#hexadecimal) literal. They can include digits ($\mathrm{0 - 9}$) and the letters $\mathrm{a - f}$ and $\mathrm{A - F}$. Note, that the case of a character does not change its value. Therefore: $\mathrm{0xa}$ = $\mathrm{0xA}$ = $10$ and $\mathrm{0xf}$ = $\mathrm{0xF}$ = $15$. + +* A leading $\mathrm{0o}$ (or $\mathrm{0O}$) indicates a [octal integer](/book/integers#octal) literals. They can include only the digits $\mathrm{0 - 7}$. + +* A leading $\mathrm{0b}$ (or $\mathrm{0B}$) indicates a [binary integer](/book/integers#binary) literal. THey can only include the digits $0$ and $1$. + + + Be wary that in Tact integer literals with a leading $0$ are still considered decimals, unlike in JavaScript/TypeScript where leading $0$ indicates an octal! + + +Some examples of integer literals: + +```tact +// decimal, base 10: +0, 42, 1_000, 020 + +// hexadecimal, base 16: +0xABC, 0xF, 0x0011 + +// octal, base 8: +0o777, 0o001 + +// binary, base 2: +0b01111001_01101111_01110101_00100000_01100001_01110010_01100101_00100000_01100001_01110111_01100101_01110011_01101111_01101101_01100101 +``` + +Read more about integers and [`Int{:tact}`](/book/integers) type on the dedicated page: [Integers](/book/integers). + +### Boolean literals + +The [`Bool{:tact}`](/book/types#booleans) type has only two literal values: `true{:tact}` and `false{:tact}`. + +```tact +true == true; +true != false; +``` + +Read more about booleans and [`Bool{:tact}`](/book/types#booleans) type in the dedicated chapter: [Booleans](/book/types#booleans). + +### String literals + +A string literal is zero or more characters enclosed in double (`"`) quotation marks. All string literals are objects of [`String{:tact}`][p] type. + +```tact +"foo" +"1234" + +// Note, that at the moment Tact strings can't have escape characters in them: +"line \n another"; // SYNTAX ERROR!, see: https://github.com/tact-lang/tact/issues/25 + +// This means, that double quotes inside strings are also prohibited: +"this \"can't be!\""; // SYNTAX ERROR! +``` + +Read more about strings and [`String{:tact}`][p] type there: [Primitive types][p]. + +### `null` literal + +The `null{:tact}` value is written with a `null{:tact}` literal. It's **not** an [identifier](#identifiers) and doesn't refer to any object. It's also **not** an instance of a [primitive type][p]. Instead, `null{:tact}` represents a lack of identification and the intentional absence of any value. + +```tact +let var: Int? = null; // variable, which can hold null value +var = 42; +if (var != null) { + var!! + var!!; +} +``` + +Read more about working with `null{:tact}` in the dedicated chapter: [Optionals](/book/composite-types#optionals). + +## Identifiers + +An identifier is a sequence of characters in the code that _identifies_ a [variable](/book/statements#let), [constant](/book/constants), [map](/book/types#maps) and a [function](/book/functions), as well as a [Struct][s], [Message][m], [contract](/book/types#contract), [trait](/book/types#trait), or their fields and methods. Identifiers are case-sensitive and not quoted. + +In Tact, identifiers can contain latin lowercase letters (`a-z`), latin uppercase letters (`A-Z`), underscores (`_`) and digits ($\mathrm{0 - 9}$), but may not start with a digit. An identifier differs from a [string](#string-literals) in that a string is data, while an identifier is part of the code. + +Note, that when identifiers for [primitive types][p] start with an uppercase letter. Used-defined [composite types](/book/composite-types), such as [Structs][s] and [Messages][m] also must be capitalized. + +## Instantiation + +You can create instances of the following types: + +* [Structs][s] +* [Messages][m] + +```tact +struct StExample { + fieldInit: Int = 1; + fieldUninit: Int; +} + +fun example() { + StExample{ fieldUninit: 2 }; // instance with default value of fieldInit + StExample{ fieldInit: 0, fieldUninit: 2 }; // instance with both fields set +} +``` + +## Field access + +You can directly access fields of the following types: + +* [Structs][s] +* [Messages][m] + +```tact +struct StExample { + fieldInit: Int = 1; + fieldUninit: Int; +} + +fun example(): Int { + let struct: StExample = StExample{ fieldUninit: 2 }; // instantiation + + struct.fieldInit; // access a field + return struct.fieldUninit; // return field value from the function +} +``` + +## Extension function call + +[Extension functions](/book/functions#extension-function) are defined only on specific types. They can be called similar to method calls in many other languages: + +```tact +42.toString(); // toString() is a stdlib function that is defined on Int type +``` + +## Static function call + +Anywhere in the function body, a global [static function](/book/functions#global-static-functions) or an internal function of a contract can be called: + +```tact +contract ExampleContract { + init() {} + receive() { + now(); // now() is a static function of stdlib + let expiration: Int = now() + 1000; // operation and variable declaration + expiration = self.answerQuestion(); // internal function + } + fun answerQuestion(): Int { + return 42; + } +} +``` + +## `initOf` + +Expression `initOf{:tact}` computes initial state (`StateInit{:tact}`) of a [contract](/book/types#contracts): + +```tact +// argument values for the init() function of the contract +// ↓ ↓ +initOf ExampleContract(42, 100); // returns a Struct StateInit{} +// --------------- +// ↑ +// name of the contract +``` + +Where `StateInit{:tact}` is a built-in [Struct][s], that consists of: + +Field | Type | Description +:----- | :----------------- | :---------- +`code` | [`Cell{:tact}`][p] | initial code of the contract (the compiled bytecode) +`data` | [`Cell{:tact}`][p] | initial data of the contract (arguments of `init(){:tact}` function of the contract) + +[p]: /book/types#primitive-types +[s]: /book/composite-types#structs +[m]: /book/composite-types#messages \ No newline at end of file diff --git a/pages/book/integers.mdx b/pages/book/integers.mdx index 63acce82..a1c2c60e 100644 --- a/pages/book/integers.mdx +++ b/pages/book/integers.mdx @@ -9,7 +9,7 @@ It's capable of storing integers between $-2^{256}$ and $2^{256} - 1.$ ## Notation -Tact supports various ways of writing primitive values of `Int{:tact}` (integer literals). +Tact supports various ways of writing primitive values of `Int{:tact}` as [integer literals](/book/expressions#integer-literals). Most of the notations allow adding underscores (`_`) in-between digits, except for: * Representations in strings, as seen in [nano-tons](#nano-tons) case. diff --git a/pages/book/send.mdx b/pages/book/send.mdx index cb9d2144..54103fd0 100644 --- a/pages/book/send.mdx +++ b/pages/book/send.mdx @@ -55,7 +55,7 @@ send(SendParameters{ ## Deploy contract -To deploy a contract you need to calculate its address and init package, then send it with an initial message. You can always send an init package with a message and it would be ignored, but would cost more than the message without an init package. +To deploy a contract you need to calculate its address and initial state with [`initOf{:tact}`](/book/expressions#initof), then send them in the initialization message: ```tact let init: StateInit = initOf SecondContract(arg1, arg2); @@ -70,4 +70,4 @@ send(SendParameters{ data: init.data, body: "Hello, World!".asComment() }); -``` +``` \ No newline at end of file diff --git a/pages/book/types.mdx b/pages/book/types.mdx index 18860eb5..782cbdce 100644 --- a/pages/book/types.mdx +++ b/pages/book/types.mdx @@ -110,6 +110,8 @@ Learn more about them on a dedicated page about [composite types](/book/composit Contracts are the main entry of a smart contract on the TON blockchain. It holds all [functions](/book/functions), [getters](/book/functions#getter-functions), and [receivers](/book/functions#receiver-functions) of a TON contract. +Contracts and [traits](#traits) have a built-in [identifier](/book/expressions#identifiers) `self{:tact}`, which is used for referring to their fields (persistent state variables) and methods (internal functions). + ```tact // Basic example of a counter contract: contract HelloWorld {