Глубокое погружение в Fift
Эта страница переведена сообществом на русский язык, но нуждается в улучшениях. Если вы хотите принять участие в переводе свяжитесь с @alexgton.
Высокоуровневый стековый язык Fift используется для локальной манипуляции ячейками и другими примитивами TVM, в основном для преобразования ассемблерного кода TVM в код контракта bag-of-cells.
В этом разделе описывается взаимодействие с специфичными для TON функциями на очень низком уровне. Требуется серьезное понимание основ стековых языков.
Простая арифметика
Вы можете использовать интерпретатор Fift как калькулятор, записывая выражения в обратной польской нотации.
6 17 17 * * 289 + .
2023 ok
Стандартный выход
27 emit ."[30;1mgrey text" 27 emit ."[37m"
grey text ok
emit
берет число с вершины стека и выводит символ Unicode с указанным кодом в stdout.
."..."
выводит строку-константу.
Определение функций (Fift-слов)
Основной способ определения слова - заключить его значения в фигурные скобки, затем написать ":" и название слова.
{ minmax drop } : min
{ minmax nip } : max
Fift.fif
Хотя есть несколько "определяющих слов", а не только ":". Они отличаются в смысле слов, определяемых некоторыми из них, активные (работают внутри фигурных скобок), а некоторые префиксные (не требуют пробела после них):
{ bl word 1 2 ' (create) } "::" 1 (create)
{ bl word 0 2 ' (create) } :: :
{ bl word 2 2 ' (create) } :: :_
{ bl word 3 2 ' (create) } :: ::_
{ bl word 0 (create) } : create
Fift.fif
Условное выполнение
Блоки кода (разделенные фигурными скобками) могут выполняться как условно, так и безоговорочно.
{ { ."true " } { ."false " } cond } : ?. 4 5 = ?. 4 5 < ?.
false true ok
{ ."hello " } execute ."world"
hello world ok
Циклы
// ( l c -- l') deletes first c elements from list l
{ ' safe-cdr swap times } : list-delete-first
GetOpt.fif
Слово цикла times
принимает два аргумента — назовем их cont
и n
— и выполняет cont
n
раз.
Здесь list-delete-first
берет продолжение safe-cdr
(команда удаления заголовка из списка в стиле Lisp), помещает его под c
, а затем c
times удаляет заголовок из списка, присутствующего в стеке.
Есть также слова while
и until
.
Комментарии
{ 0 word drop 0 'nop } :: //
{ char " word 1 { swap { abort } if drop } } ::_ abort"
{ { bl word dup "" $= abort"comment extends after end of file" "*/" $= } until 0 'nop } :: /*
Fift.fif
Комментарии определены в Fift.fif
. Однострочный комментарий начинается с //
и продолжается до конца строки; многострочный комментарий начинается с /*
и заканчивается */
.
Давайте разберемся, почему они так работают.
Программа Fift по сути является последовательностью слов, каждое из которых каким-либо образом преобразует стек или определяет новые слова. Первая строка Fift.fif
(код показан выше) является объявлением нового слова //
.
Комментарии должны работать даже при определении новых слов, поэтому они должны работать во вложенной среде. Вот почему они определены как активные слова с помощью ::
. Действия создаваемого слова перечислены в фигурных скобках:
0
: ноль помещается в стекword
: эта команда считывает символы до тех пор, пока не будет достигнут один, равный вершине стека, и помещает считанные данные в стек как строку. Ноль — это особый случай: здесьword
пропускает начальные пробелы и затем читает до конца текущей входной строки.drop
: верхний элемент (данные комментария) удаляется из стека.0
: ноль снова помещается в стек — число результатов, использованное потому, что слово определено как::
.nop
помещает токен выполнения, ничего не делая при вызове. Это практически эквивалентно{ nop }
.
Использование Fift для определения кодов сборки TVM
x{00} @Defop NOP
{ 1 ' @addop does create } : @Defop
{ tuck sbitrefs @ensurebitrefs swap s, } : @addop
{ @havebitrefs ' @| ifnot } : @ensurebitrefs
{ 2 pick brembitrefs 1- 2x<= } : @havebitrefs
{ rot >= -rot <= and } : 2x<=
...
Asm.fif (порядок строк обратный)
@Defop
проверяет, достаточно ли места для кода операции (@havebitrefs
), и если его нет, он продолжает запись в другой сборщик (@|
; также известно как неявный переход). Вот почему вы обычно не хотите писать x{A988} s
в качестве кода операции: для размещения этого кода операции может быть недостаточно места, поэтому компиляция завершится неудачей; вместо этого вам следует написать x{A988} @addop
.
Вы можете использовать Fift для включения большого bag-of-cells в контракт:
<b 8 4 u, 8 4 u, "fift/blob.boc" file>B B>boc ref, b> <s @Defop LDBLOB
Эта команда определяет код операции, который при включении в программу записывает x{88}
(PUSHREF
) и ссылку на предоставленный bag-of-cells. Поэтому, когда запускается инструкция LDBLOB
, она помещает ячейку в стек TVM.
Специальные возможности
- Шифрование Ed25519
- newkeypair - генерирует пару закрытый-открытый клю ч
- priv>pub - генерирует открытый ключ из закрытого
- ed25519_sign[_uint] - генерирует подпись по заданным данным и закрытому ключу
- ed25519_chksign - проверяет подпись Ed25519
- Взаимодействие с TVM
- runvmcode и подобное - вызывает TVM с фрагментом кода, взятым из стека
- Запись BOC в файлы:
boc>B ".../contract.boc" B>file
Продолжаем изучение
- Fift: Краткое введение Николая Дурова