Skip to content

Commit 569bc55

Browse files
authored
feat(tolk/grammar): support type int = builtin and use new syntax for stubs (#129)
Fixes #128
1 parent fbf19c6 commit 569bc55

File tree

7 files changed

+15838
-15765
lines changed

7 files changed

+15838
-15765
lines changed

server/src/e2e/tolk/testcases/types2/assign-smartcast.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Smart cast on assignment, union type value
2727
========================================================================
2828
fun main() {
2929
val value: int | bool | null = 10 as int | bool;
30-
//! ^ int | bool | null
30+
//! ^ int | bool
3131
value;
3232
//! ^ int | bool
3333
}

server/src/languages/tolk/TypeInferer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ export class TypeInferer {
700700
if (underlyingType === null) return null
701701

702702
const underlyingTypeName = underlyingType.text
703-
if (underlyingTypeName === "builtin_type") {
703+
if (underlyingTypeName === "builtin_type" || underlyingTypeName === "builtin") {
704704
const name = resolved.name()
705705
switch (name) {
706706
case "void": {

server/src/languages/tolk/stubs/stubs.tolk

Lines changed: 97 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,96 @@
11
/// `int` is the primitive 257-bit signed integer type.
2-
type int = builtin_type;
3-
4-
/// `bool` is the classical boolean type, which can hold only two values: `true` and `false`.
5-
/// It is convenient for boolean and logical operations, as well as for storing flags.
6-
///
7-
/// There are no implicit type conversions in Tolk, so addition `+` of two boolean values is
8-
/// not possible. However, many comparison operators are available.
9-
///
10-
/// Persisting bools to state is very space-efficient, as they only occupy 1 bit.
11-
/// Storing 1000 bools in state [costs](https://ton.org/docs/develop/smart-contracts/fees#how-to-calculate-fees)
12-
/// about 0.00072 TON per year.
13-
type bool = builtin_type;
14-
15-
/// `cell` is a primitive and a data structure, which ordinarily consists of up to 1023 continuously
16-
/// laid out bits and up to 4 references (refs) to other cells. Circular references are forbidden and
17-
/// cannot be created by means of [TVM], which means cells can be viewed as [quadtrees]
18-
/// or [directed acyclic graphs (DAGs)][dag] of themselves.
19-
///
20-
/// Contract code itself is represented by a tree of cells.
21-
///
22-
/// Cells and cell primitives are bit-oriented, not byte-oriented: [TVM] regards data kept in cells
23-
/// as sequences (strings or streams) of up to 1023 bits, not bytes. If necessary, contracts are
24-
/// free to use, for example, 21-bit integer fields serialized into [TVM] cells, thus using fewer
25-
/// persistent storage bytes to represent the same data.
26-
///
27-
/// [TVM]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
28-
/// [quadtrees]: https://en.wikipedia.org/wiki/Quadtree
29-
/// [dag]: https://en.wikipedia.org/wiki/Directed_acyclic_graph
30-
type cell = builtin_type;
31-
32-
/// `slice` is a cell manipulation primitive used for cell parsing instructions.
33-
/// Unlike cells, slices are mutable and allow extraction or loading of data previously
34-
/// stored in cells via serialization instructions. Also unlike cells, values of type `slice`
35-
/// appear only on the [TVM] stack and cannot be stored in persistent storage.
36-
/// This means, for example, that persistent storage fields with type `slice` would actually
37-
/// be stored as cells under the hood.
38-
///
39-
/// The `slice` type represents either the remainder of a partially parsed cell or a value (subcell)
40-
/// residing inside such a cell, extracted from it by a parsing instruction.
41-
///
42-
/// [TVM]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
43-
type slice = builtin_type;
44-
45-
/// `builder` is a cell manipulation primitive used for cell creation instructions.
46-
/// They are immutable just like cells and allow constructing new cells from previously
47-
/// stored values and cells.
48-
///
49-
/// Unlike cells, values of type `builder` appear only on the [TVM] stack and cannot
50-
/// be stored in persistent storage. This means, for example, that persistent storage
51-
/// fields with type `builder` are actually stored as cells under the hood.
52-
///
53-
/// The `builder` type represents partially composed cells, for which fast operations
54-
/// to append integers, other cells, references to other cells, and many other operations
55-
/// are defined.
56-
///
57-
/// [TVM]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
58-
type builder = builtin_type;
59-
60-
/// `continuation` is a primitive type that represents executable [TVM] code.
61-
/// Continuations are used to manage execution flow in [TVM] programs and serve as
2+
type int = builtin
3+
4+
/// `bool` is a classic boolean type, which can hold only two values: `true` and `false`.
5+
/// At the TVM (TON virtual machine) level, it's an integer -1 or 0.
6+
/// Note: `boolVar as int` is possible, but remember, that true is -1, not 1!
7+
type bool = builtin
8+
9+
/// `cell` is a data structure, which can hold of up to 1023 bits (not bytes!)
10+
/// and up to 4 references (refs) to other cells.
11+
/// Both contract code and contract state are represented by a tree of cells.
12+
/// See docs: https://docs.ton.org/v3/documentation/data-formats/tlb/cell-boc
13+
type cell = builtin
14+
15+
/// `slice` is a "cell opened for reading".
16+
/// When you call [cell.beginParse], you get a `slice`, from which you can load binary data
17+
/// or high-level structures with [T.fromSlice].
18+
type slice = builtin
19+
20+
/// `builder` is a "cell at the stage of creation".
21+
/// When you call [beginCell], you get a `builder`, populate it with binary data or structures,
22+
/// and after [builder.endCell], you get a `cell`.
23+
type builder = builtin
24+
25+
/// `continuation` are "executable cells" representing executable TVM bytecode.
26+
/// They are used to manage execution flow in TVM programs and serve as
6227
/// the basis for function calls, exception handling, and control flow operations.
63-
///
64-
/// In practical terms, continuations can be viewed as "executable cells" - they contain
65-
/// bytecode that can be executed by the virtual machine. Smart contract code itself
66-
/// is stored as a continuation.
67-
///
68-
/// [TVM]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
69-
type continuation = builtin_type;
28+
type continuation = builtin
7029

71-
/// `tuple` is an ordered collection type that can hold up to 255 elements of any type.
72-
/// Unlike tensors which are represented as multiple stack entries, tuples are stored
73-
/// as a single composite value on the [TVM] stack.
74-
///
75-
/// Tuples provide dynamic data structures where the number and types of elements
76-
/// can vary at runtime. They are particularly useful for handling variable-length
77-
/// data and implementing complex data structures like lisp-like lists.
78-
///
79-
/// Individual elements can be accessed using indexing operations (e.g. `someTuple.0`),
80-
/// and tuples can be modified by adding, removing, or replacing elements. Empty tuples are also valid.
81-
///
82-
/// Tuples occupy only one stack slot regardless of their size.
83-
///
84-
/// [TVM]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
85-
type tuple = builtin_type;
30+
/// `tuple` is a collection from 0 to 255 elements of any type.
31+
/// You can push, pop, access individual elements as `someTuple.0`.
32+
/// A tuple occupies one stack slot regardless of its size.
33+
type tuple = builtin
8634

87-
/// `coins` is a specialized primitive type for representing amounts of Toncoins
88-
/// in the smallest possible unit (nanotons). One Toncoin equals 10^9 nanotons.
89-
///
90-
/// The `coins` type is essentially a 16-bit variable-length integer with special semantic
91-
/// meaning and dedicated operations for monetary calculations. It ensures precision
92-
/// in financial operations.
93-
///
94-
/// You can create `coins` values using the `ton()` function with human-readable
95-
/// string literals: `ton("1.5")` creates 1.5 TON worth of nanotons.
96-
///
97-
/// Arithmetic operations on `coins` degrade to 257-bit `int` type, allowing mathematical
98-
/// operations while maintaining type safety for monetary values.
99-
///
100-
/// Example:
101-
/// ```
102-
/// var amount: coins = ton("1.5");
103-
/// var total: coins = amount + ton("0.5");
104-
/// ```
105-
///
106-
/// [fees]: https://docs.ton.org/develop/smart-contracts/fees
107-
type coins = builtin_type;
108-
109-
/// `address` is a primitive type that represents a [smart contract address] in TON Blockchain.
110-
///
111-
/// [smart contract address]: https://docs.ton.org/learn/overviews/addresses#address-of-smart-contract
112-
type address = builtin_type;
35+
/// `address` represents an internal/external/none address.
36+
/// Most likely, you'll use it for internal addresses — "an address of a smart contract".
37+
/// It's `slice` under the hood. `someAddress as slice` is also possible.
38+
/// See docs: https://docs.ton.org/learn/overviews/addresses#address-of-smart-contract
39+
type address = builtin
11340

11441
/// `never` is a special type that represents computations that never complete normally.
115-
/// Functions that always throw exceptions return `never`.
116-
///
117-
/// When a function returns `never`, the compiler knows that code after calling
118-
/// such a function is unreachable, eliminating the need for explicit return statements.
119-
///
120-
/// Example:
121-
/// ```
122-
/// fun alwaysThrows(): never { throw 123 }
123-
///
124-
/// fun main(val: int) {
125-
/// if (val == 100) {
126-
/// alwaysThrows();
127-
/// debug.printString("This line is unreachable");
128-
/// }
129-
/// }
130-
/// ```
131-
type never = builtin_type;
42+
/// A functions that always throw an exception returns `never`, and the compiler knows
43+
/// that any code after it is unreachable.
44+
type never = builtin
45+
46+
/// `int8`, `int32`, `int222`, etc. is "a fixed-width signed integer with N bits", N <= 257.
47+
/// Note: it's still `int` at runtime, you can assign "100500" to "int8":
48+
/// overflow will happen at serialization to a cell/builder, NOT at assignment.
49+
type intN = builtin
50+
51+
/// `uint32`, `uint64`, `uint111`, etc. is "a fixed-width unsigned integer with N bits", N <= 256.
52+
/// Note: it's still `int` at runtime, you can assign "100500" to "uint8":
53+
/// overflow will happen at serialization to a cell/builder, NOT at assignment.
54+
type uintN = builtin
55+
56+
/// `coins` is a special primitive representing "nanotoncoins". One TON = 10^9 nanotoncoins.
57+
/// You can create coins with `ton()` function: `ton("0.05")` (actually, `int` 50000000 at runtime).
58+
/// Arithmetic operations on `coins` degrade to 257-bit `int` type.
59+
type coins = builtin
60+
61+
/// `varint16` is `int` at runtime, but serialized as "variadic signed int", -2^119 <= X < 2^119.
62+
type varint16 = builtin
63+
64+
/// `varuint16` is `int` at runtime, but serialized as "variadic unsigned int", 0 <= X < 2^120.
65+
type varuint16 = builtin
66+
67+
/// `varint32` is `int` at runtime, but serialized as "variadic signed int", -2^247 <= X < 2^247.
68+
type varint32 = builtin
69+
70+
/// `varuint32` is `int` at runtime, but serialized as "variadic unsigned int", 0 <= X < 2^248.
71+
type varuint32 = builtin
72+
73+
/// `bits256`, `bits111`, etc. is "a fixed-width slice with N bits and 0 refs", N <= 1023.
74+
/// Note: use `as` operator to convert `slice` to `bitsN`: `someSlice as bits256`
75+
/// (manually writing `as` enforces you to think that this conversion is correct).
76+
/// Note: similar to `intN`, you can assign an invalid slice to `bitsN`,
77+
/// an error will be fired at serialization with [T.toCell] and similar, NOT at assignment.
78+
type bitsN = builtin
79+
80+
/// `bytes8`, `bytes99`, etc. is a convenient alias for `bits(N*8)`
81+
type bytesN = builtin
82+
83+
/// `map<K, V>` is "a map from a key K to a value V".
84+
/// Internally, it's an "optional cell": an empty map is `null`, a non-empty points to a root cell.
85+
/// Restrictions for K and V types:
86+
/// - a key must be fixed-with; valid: int32, uint64, address, bits256, Point; invalid: int, coins
87+
/// - a value must be serializable; valid: int32, coins, AnyStruct, Cell<AnyStruct>; invalid: int, builder
88+
type map<K, V> = builtin
13289

13390
/// `void` is the unit type representing the absence of a meaningful value.
134-
/// It is used to indicate that a function does not return any useful data
135-
/// or that a computation produces no result.
136-
///
137-
/// Functions with return type `void` are executed for their side effects
138-
/// (like modifying global state, sending messages, or dumping output)
139-
/// rather than for producing a return value.
140-
///
141-
/// Example:
142-
/// ```
143-
/// fun processMessage(): void { ... }
144-
/// ```
145-
///
146-
/// Note: function without return type is NOT equivalent to `void`, but rather `auto`.
147-
type void = builtin_type;
148-
149-
/// `null` is a primitive type that represents the absence of a value.
150-
/// It is the type of the `null` literal and serves as the "nothing" value
151-
/// in nullable type expressions (e.g. `int?`).
152-
///
153-
/// In Tolk's type system, `null` is used to construct nullable types:
154-
/// `int?` is equivalent to `int | null`, meaning a value that can be
155-
/// either an integer or null.
156-
///
157-
/// The `null` type ensures null safety through compile-time checks,
158-
/// preventing null pointer errors that are common in other languages.
159-
/// You must explicitly check for null before using potentially null values.
160-
///
161-
/// Example:
162-
/// ```
163-
/// var maybeValue: int? = null;
164-
/// ```
165-
type null = builtin_type;
91+
/// It's similar to both `void` and `unit` in other languages.
92+
/// Note: a function without return type means "auto infer", NOT "void".
93+
type void = builtin
16694

16795
/// `self` is a special return type marker used in method definitions to indicate
16896
/// that the method returns the same object it was called on, enabling method chaining.
@@ -182,69 +110,25 @@ type null = builtin_type;
182110
/// ```
183111
/// someBuilder.storeInt(42, 32).storeInt(24, 32)
184112
/// ```
185-
type self = builtin_type;
186-
187-
/// Represents a fixed-width unsigned integer of `N` bits, where `N` can range from 1 to 256.
188-
///
189-
/// Example:
190-
/// ```
191-
/// struct (0x7e8764ef) IncrementMessage {
192-
/// queryID: uint64; // precise 64-bit unsigned integer serialization/deserialization
193-
/// increaseBy: uint32; // precise 32-bit unsigned integer serialization/deserialization
194-
/// }
195-
/// ```
196-
type uintN = builtin_type;
197-
198-
/// Represents a fixed-width signed integer of `N` bits, where `N` can range from 1 to 257.
199-
///
200-
/// Example:
201-
/// ```
202-
/// struct (0x7e8764ef) IncrementMessage {
203-
/// queryID: uint64; // precise 64-bit unsigned integer serialization/deserialization
204-
/// increaseBy: int32; // precise 32-bit signed integer serialization/deserialization
205-
/// }
206-
/// ```
207-
type intN = builtin_type;
208-
209-
/// Represents an unsigned variable size-width signed integer of 32 bits.
210-
type varuint32 = builtin_type;
211-
212-
/// Represents a signed variable size-width signed integer of 32 bits.
213-
type varint32 = builtin_type;
214-
215-
/// Represents an unsigned variable size-width signed integer of 16 bits.
216-
type varuint16 = builtin_type;
217-
218-
/// Represents a signed variable size-width signed integer of 16 bits.
219-
type varint16 = builtin_type;
113+
type self = builtin;
220114

221-
/// Represents a fixed-length sequence of `N` bits, where `N` can range from 1 to 1023.
115+
/// `null` is a primitive type that represents the absence of a value.
116+
/// It is the type of the `null` literal and serves as the "nothing" value
117+
/// in nullable type expressions (e.g. `int?`).
222118
///
223-
/// At the TVM level, `bitsN` is backed by a `slice`. This type is used for handling
224-
/// raw binary data of a known, fixed size.
119+
/// In Tolk's type system, `null` is used to construct nullable types:
120+
/// `int?` is equivalent to `int | null`, meaning a value that can be
121+
/// either an integer or null.
225122
///
226-
/// Example:
227-
/// ```
228-
/// struct (0x7e8764ef) MessageWithSignature {
229-
/// message: bits256; // precise 256-bit binary data serialization/deserialization
230-
/// signature: bits256; // precise 256-bit binary data serialization/deserialization
231-
/// }
232-
/// ```
233-
type bitsN = builtin_type;
234-
235-
/// Represents a fixed-length sequence of `N` bytes. This is a convenient alias for `bits(N * 8)`.
236-
/// `N` can range from 1 to 127.
123+
/// The `null` type ensures null safety through compile-time checks,
124+
/// preventing null pointer errors that are common in other languages.
125+
/// You must explicitly check for null before using potentially null values.
237126
///
238127
/// Example:
239128
/// ```
240-
/// struct (0x7e8764ef) MessageWithSignature {
241-
/// message: bytes32; // precise 32-byte binary data serialization/deserialization
242-
/// signature: bytes32; // precise 32-byte binary data serialization/deserialization
243-
/// }
129+
/// var maybeValue: int? = null;
244130
/// ```
245-
type bytesN = builtin_type;
246-
247-
type builtin_type = void;
131+
type null = builtin_type;
248132

249133
// builtin operators
250134
// they are internally stored as functions, because at IR level, there is no difference

server/src/languages/tolk/tree-sitter-tolk/grammar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const TOLK_GRAMMAR = {
7676
optional(field("type_parameters", $.type_parameters)),
7777
"=",
7878
optional("|"),
79-
field("underlying_type", $._type_hint),
79+
field("underlying_type", choice($._type_hint, $.builtin_specifier)),
8080
optional(";"),
8181
),
8282
),

server/src/languages/tolk/tree-sitter-tolk/src/grammar.json

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/src/languages/tolk/tree-sitter-tolk/src/node-types.json

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)