Язык TL-B
Эта страница переведена сообществом на русский язык, но нуждается в улучшениях. Если вы хотите принять участие в переводе свяжитесь с @alexgton.
TL-B (Type Language - Binary) служит для описания системы типов, конструкторов и существующих функций. Например, мы
можем использовать схемы TL-B для построения двоичных структур, связанных с блокчейном TON. Специальные парсеры TL-B могут считывать схемы для
десериализации двоичных данных в различные объекты. TL-B описывает схемы данных для объектов Cell
. Если вы не знакомы с Cells
, пожалуйста, прочтите статью Ячейки пакеты Ячеек (BOC).
Общие сведения
Мы называем любой набор конструкций TL-B документами TL-B. Документ TL-B обычно состоит из объявлений типов (
т. е. их конструкторов) и функциональных комбинаторов. Объявление каждого комбинатора заканчивается точкой с запятой (;
).
Вот пример возможного объявления комбинатора:


Конструкторы
Левая часть каждого уравнения описывает способ определения или сериализации значения типа, указанного в правой части. Такое описание начинается с имени конструктора.


Конструкторы используются для указания типа комбинатора, включая состояние при сериализации. Например, конструкторы
также могут использоваться, когда вы хотите указать op
(код операции) в запросе к смарт-контракту в TON.
// ....
transfer#5fcc3d14 <...> = InternalMsgBody;
// ....
- имя конструктора:
transfer
- префиксный код конструктора:
#5fcc3d14
Обратите внимание, что за каждым именем конструктора сразу следует необязательный тег конструктора, такой как #_
или $10
, который
описывает битовую строку, используемую для кодирования (сериализации) рассматриваемого конструктора.
message#3f5476ca value:# = CoolMessage;
bool_true$0 = Bool;
bool_false$1 = Bool;
Левая часть каждого уравнения описывает способ определения или сериализации значения типа, указанного в
правой части. Такое описание начинается с имени конструктора, например message
или bool_true
, за которым сразу следует необязательный тег конструктора, например #3f5476ca
или $0
, который описывает биты, используемые для кодирования (
сериализации) рассматриваемого конструктора.
конструктор | сериализация |
---|---|
some#3f5476ca | 32-битный uint сериализуется из шестнадцатеричного значения |
some#5fe | 12-битный uint сериализуется из шестнадцатеричного значения |
some$0101 | сериализует 0101 необработанные биты |
some или some# | сериализует crc32(уравнение) | 0x80000000 |
some#_ или some$_ или _ | не сериализуется |
Имена конструкторов (some
в этом примере) используются как переменные в codegen. Например:
bool_true$1 = Bool;
bool_false$0 = Bool;
Тип Bool
имеет два тега 0
и 1
. Псевдокод Codegen может выглядеть так:
class Bool:
tags = [1, 0]
tags_names = ['bool_true', 'bool_false']
Если вы не хотите определять имя для текущего конструктора, просто передайте _
, например, _ a:(## 32) = 32Int;
Теги конструктора могут быть заданы либо в двои чной (после знака доллара), либо в шестнадцатеричной нотации (после знака решетки). Если
тег не указан явно, анализатор TL-B должен вычислить 32-битный тег конструктора по умолчанию, хешируя с помощью алгоритма CRC32 текст "уравнения" с | 0x80000000
, определяя этот конструктор определенным образом. Поэтому пустые теги
должны быть явно указаны #_
или $_
.
Этот тег будет использоваться для определения текущего типа битовой строки в процессе десериализации. Например, у нас есть 1 битовая строка 0
,
если мы скажем TLB проанализировать эту битовую строку в типе Bool
, он проанализирует ее как Bool.bool_false
.
Допустим, у нас есть более сложные примеры:
tag_a$10 val:(## 32) = A;
tag_b$00 val(## 64) = A;
Если мы проанализируем 1000000000000000000000000000000000000001
(1 и 32 нуля и 1) в типе TLB A
- сначала нам нужно получить первые
два бита для определения тега. В этом примере 10
- это два первых бита, и они представляют tag_a
. Теперь мы знаем, что следующие 32
бита - это переменная val
, 1
в нашем примере. Некоторые "проанализированные" переменные псевдокода могут выглядеть так:
A.tag = 'tag_a'
A.tag_bits = '10'
A.val = 1
Все имена конструкторов должны быть разными, а теги конструкторов для одного типа должны составлять префиксный код (иначе десериализация не будет уникальной); т. е. ни один тег не может быть префиксом любого другого в том же типе.
Максимальное количество конструкторов для одного типа: 64
Максимальное количество бит для тега: 63
example_a$10 = A;
example_b$01 = A;
example_c$11 = A;
example_d$00 = A;
Псевдокод Codegen мож ет выглядеть так:
class A:
tags = [2, 1, 3, 0]
tags_names = ['example_a', 'example_b', 'example_c', 'example_d']
example_a#0 = A;
example_b#1 = A;
example_c#f = A;
Псевд окод Codegen может выглядеть так:
class A:
tags = [0, 1, 15]
tags_names = ['example_a', 'example_b', 'example_c']
Если вы используете тег hex
, имейте в виду, что он будет сериализован как 4 бита для каждого шестнадцатеричного символа. Максимальное значение — 63-битное целое число без знака. Это означает:
a#32 a:(## 32) = AMultiTagInt;
b#1111 a:(## 32) = AMultiTagInt;
c#5FE a:(## 32) = AMultiTagInt;
d#3F5476CA a:(## 32) = AMultiTagInt;
конструктор | сериализация |
---|---|
a#32 | 8-битный uint сериализуется из шестнадцатеричного значения |
b#1111 | 16-битный uint сериализуется из шестнадцатеричного значения |
c#5FE | 12-битный uint сериализуется из шестнадцатеричного значения |
d#3F5476CA | 32-битный uint сериализуется из шестнадцатеричного значения |
Также шестнадцатеричные значения разрешены как в верхнем, так и в нижнем регистре.
Подробнее о шестнадцатеричных тегах
В дополнение к классическому определению шестнадцатеричного тега, за шестнадцатеричным числом может следовать символ подчеркивания. Это означает, что тег равен указанному шестнадцатеричному числу без младшего бита. Например, есть такая схема:
vm_stk_int#0201_ value:int257 = VmStackValue;
И тег на самом деле не равен 0x0201
. Чтобы вычислить его, нам нужно удалить LSb из двоичного представления 0x0201
:
0000001000000001 -> 000000100000000
Таким образом, тег равен 15-битному двоичному числу 0b000000100000000
.