# Функции для работы с генерацией кода Во время выполнения вычислений можно сгенерировать код, состоящий из узлов [S-expressions](/docs/s_expressions). Для этого используется механизм представления кода, упакованного в [ресурс](../types/special.md). После конструирования кода можно подставить его в основную програму с помощью функции [EvaluateCode](#evaluatecode). Для отладки сконвертировать код в строку можно с помощью функции [FormatCode](#formatcode). Возможные типы узлов в S-expressions, которые можно использовать для генерации кода: * Атом - нетипизированная строка из нуля и более символов. * Список - последовательность из нуля и более узлов. Соответствует типу `кортеж` в SQL. * Вызов встроенной функции - состоит из имени, выраженного атомом, и последовательности из нуля и более узлов, которые являются аргументами этой функции. * Объявление лямбда функции - состоит из объявления имен аргументов и узла, который является корнем тела этой лямбда функции. * Аргумент лямбды функции - узел, который может использоваться только внутри тела лямбда-функции. * Мир - специальный узел, маркирующий операции ввода/вывода. Узлы S-expressions образуют ориентированный граф. При этом атомы - всегда листовые узлы, так как не могут содержать дочерних узлов. В текстовой записи S-expressions записываются следующим образом: * Атом - `'"foo"`. Символ апострофа (') является признаком цитирования последующей строки, обычно заключенной в кавычки. * Список - `'("foo" "bar")`. Символ апострофа (') является признаком того, что в скобках не будет вызова функции. * Вызов встроенной функции - `(foo "bar")`. Первый элемент внутри скобок - обязательное имя функции, а далее указываются ее аргументы. * Объявление лямбда функции - `(lambda '(x y) (+ x y))`. После ключевого слова `lambda` стоит список из имен аргументов, за которым следует тело лямбда функции. * Аргумент лямбда функции - `x`. В отличие от атома, строка без символа апострофа (') является ссылкой на имя в текущей области видимости. При объявлении лямбда функции в область видимости тела добавляются имена аргументов, причем при необходимости скрывается имя из объемлющей области видимости. * Мир - `world`. ## FormatCode Сериализация кода в виде [S-expressions](/docs/s_expressions). Код не должен содержать свободных аргументов функций, т.е. для сериализации кода лямбда функции нужно передавать ее целиком, а не выражения, потенциально содержащие аргументы лямбда функции. ### Примеры ```yql SELECT FormatCode(AtomCode("foo")); -- ( -- (return '"foo") -- ) ``` ## WorldCode Построить узел кода с типом `мир`. ### Примеры ```yql SELECT FormatCode(WorldCode()); -- ( -- (return world) -- ) ``` ## AtomCode Построить узел кода с типом `атом` из строки, переданной в аргумент. ### Примеры ```yql SELECT FormatCode(AtomCode("foo")); -- ( -- (return '"foo") -- ) ``` ## ListCode Построить узел кода с типом `список` из набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода. ### Примеры ```yql SELECT FormatCode(ListCode( AtomCode("foo"), AtomCode("bar"))); -- ( -- (return '('"foo" '"bar")) -- ); SELECT FormatCode(ListCode(AsList( AtomCode("foo"), AtomCode("bar")))); -- ( -- (return '('"foo" '"bar")) -- ) ``` ## FuncCode Построить узел кода с типом `вызов встроенной функции` из строки с именем функции и набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода. ### Примеры ```yql SELECT FormatCode(FuncCode( "Baz", AtomCode("foo"), AtomCode("bar"))); -- ( -- (return (Baz '"foo" '"bar")) -- ) SELECT FormatCode(FuncCode( "Baz", AsList( AtomCode("foo"), AtomCode("bar")))); -- ( -- (return (Baz '"foo" '"bar")) -- ) ``` ## LambdaCode Построить узел кода с типом `объявление лямбда функции` можно из: * [Лямбда функции](../syntax/expressions.md#lambda), если заранее известно количество аргументов. В этом случае в качестве аргументов этой лямбда функции будут переданы узлы типа `аргумент`. * Количества аргументов и [лямбда функции](../syntax/expressions.md#lambda) с одним аргументом. В этом случае в качестве аргумента этой лямбды функции будет передан список узлов типа `аргумент`. ### Примеры ```yql SELECT FormatCode(LambdaCode(($x, $y) -> { RETURN FuncCode("+", $x, $y); })); -- ( -- (return (lambda '($1 $2) (+ $1 $2))) -- ) SELECT FormatCode(LambdaCode(2, ($args) -> { RETURN FuncCode("*", Unwrap($args[0]), Unwrap($args[1])); })); -- ( -- (return (lambda '($1 $2) (* $1 $2))) -- ) ``` ## EvaluateCode Подстановка в основную программу узла кода, переданного в аргумент. ### Примеры ```yql SELECT EvaluateCode(FuncCode("Int32", AtomCode("1"))); -- 1 $lambda = EvaluateCode(LambdaCode(($x, $y) -> { RETURN FuncCode("+", $x, $y); })); SELECT $lambda(1, 2); -- 3 ``` ## ReprCode Подстановка в основную программу узла кода, который является представлением результата вычисления выражения, переданного в аргумент. ### Примеры ```yql $add3 = EvaluateCode(LambdaCode(($x) -> { RETURN FuncCode("+", $x, ReprCode(1 + 2)); })); SELECT $add3(1); -- 4 ``` ## QuoteCode Подстановка в основную программу узла кода, который является представлением выражения или [лямбда функции](../syntax/expressions.md#lambda), переданной в аргумент. Если во время подстановки были найдены свободные аргументы лямбда функций, то они вычисляются и подставляются в код как в функции [ReprCode](#reprcode). ### Примеры ```yql $lambda = ($x, $y) -> { RETURN $x + $y }; $makeClosure = ($y) -> { RETURN EvaluateCode(LambdaCode(($x) -> { RETURN FuncCode("Apply", QuoteCode($lambda), $x, ReprCode($y)) })) }; $closure = $makeClosure(2); SELECT $closure(1); -- 3 ```