Functions for code generation
When running calculations, you can generate the code including S-expressions nodes. This uses a mechanism for packing the code in the resource. After building the code, you can insert it into the main program using the EvaluateCode function. For debugging purposes, you can convert the code to a string using the FormatCode function.
Possible node types in S-expressions that can be used for code generation:
- An atom is an untyped string of zero or more characters.
- A list is a sequence of zero or more nodes. It corresponds to the
tuple
type in SQL. - A call of a built-in function consists of a name expressed by an atom and a sequence of zero or more nodes that are arguments to this function.
- Lambda function declaration consists of declaring the names of arguments and a node that is the root of the body for this lambda function.
- The lambda function argument is a node that can only be used inside the body of the lambda function.
- World is a special node that labels I/O operations.
The S-expressions nodes form a directed graph. Atoms are always leaf nodes, because they cannot contain child nodes.
In the text representation, S-expressions have the following format:
- Atom:
'"foo"
. The apostrophe character (') denotes quoting of the next line that is usually enclosed in quotation marks. - List:
'("foo" "bar")
. The apostrophe character (') denotes that there will be no function call in parentheses. - Calling the built-in function:
(foo "bar")
. The first item inside the brackets is the mandatory name of the function followed by the function arguments. - Declaring a lambda function:
(lambda '(x y) (+ x y))
. Thelambda
keyword is followed by a list of argument names and then by the body of the lambda function. - The lambda function argument is
x
. Unlike an atom, a string without an apostrophe character (') references a name in the current scope. When declaring a lambda function, the names of arguments are added to the body's visibility scope, and, if needed, the name is hidden from the global scope. - The
world
.
FormatCode
Serializing the code as S-expressions. The code must not contain free arguments of functions, hence, to serialize the lambda function code, you must pass it completely, avoiding passing individual expressions that might contain lambda function arguments.
Examples
SELECT FormatCode(AtomCode("foo"));
-- (
-- (return '"foo")
-- )
WorldCode
Build a code node with the world
type.
Examples
SELECT FormatCode(WorldCode());
-- (
-- (return world)
-- )
AtomCode
Build a code node with the atom
type from a string passed to the argument.
Examples
SELECT FormatCode(AtomCode("foo"));
-- (
-- (return '"foo")
-- )
ListCode
Build a code node with the list
type from a set of nodes or lists of code nodes passed to arguments. In this case, lists of arguments are built in as separately listed code nodes.
Examples
SELECT FormatCode(ListCode(
AtomCode("foo"),
AtomCode("bar")));
-- (
-- (return '('"foo" '"bar"))
-- );
SELECT FormatCode(ListCode(AsList(
AtomCode("foo"),
AtomCode("bar"))));
-- (
-- (return '('"foo" '"bar"))
-- )
FuncCode
Build a code node with the built-in function call
from a string with the function name and a set of nodes or lists of code nodes passed to arguments. In this case, lists of arguments are built in as separately listed code nodes.
Examples
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
You can build a code node with the lambda function declaration
type from:
- a Lambda function, if you know the number of arguments in advance. In this case, the nodes of the
argument
type will be passed as arguments to this lambda function. - The number of arguments and a lambda function with one argument. In this case, a list of nodes of the
argument
type will be passed as an argument to this lambda function.
Examples
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
Substituting the code node passed in the argument, into the main program code.
Examples
SELECT EvaluateCode(FuncCode("Int32", AtomCode("1"))); -- 1
$lambda = EvaluateCode(LambdaCode(($x, $y) -> {
RETURN FuncCode("+", $x, $y);
}));
SELECT $lambda(1, 2); -- 3
ReprCode
Substituting the code node representing the result of evaluating an expression passed in the argument, into the main program.
Examples
$add3 = EvaluateCode(LambdaCode(($x) -> {
RETURN FuncCode("+", $x, ReprCode(1 + 2));
}));
SELECT $add3(1); -- 4
QuoteCode
Substituting into the main program the code node that represents an expression or a lambda function passed in the argument. If free arguments of lambda functions were found during the substitution, they are calculated and substituted into the code as in the ReprCode function.
Examples
$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