Блоки кода
Блок кода, это сгруппированный набор идущих подряд инструкций, которые выполняются как единое целое с возвращением результата выполнения последней из них. Блок кода, как и любая синтаксическая конструкция языка, должен завершаться точкой с запятой “;”.
Блоки кода используются для ограничения области видимости переменных. С их помощью определяется иерархия области имен и реализуется система именования свойств и методов для классов. Именованные блоки кода могут выступать в качестве локальных меток для передачи потока выполнения.
За счет того, что к блоку кода можно обратится как к единой инструкции, они могут использоваться в других операторах. Тело функции, также представляет собой блока кода, который располагается в пространстве имен определения этой функции.
ns:: { # Пространство имен ns
name {
# Пространство имен ns::name
# В конце имени "::" можно не указывать
};
:: {
# Глобальное пространство имен
...
};
{
# Локальная переменная до завершения блока кода
$local ::= 0;
};
$local; # <-- Ошибка! Локальная переменная не видна
};
func_name(val) ::= {
# Блок кода func_name::
@if($val) {
...
} @else {
...
};
};
Оформление блока кода
Блок кода всегда начинается и заканчивается на фигурные скобки («{» и «}») и завершается точкой с запятой “;”. Существуют блоки кода, которые перехватывают потоки выполнения, с помощью которых реализуются возврат и обработка ошибок.
Тип возвращаемого значения блоком кода можно указать в явном виде. Для этого, после завершающей фигурной скобки, нужно указать разрешенный тип, после чего компилятор будет проверят корретность данных внутрие блока кода, которые могут быть возвращены.
Можно указать сразу несколько типов, перечислив их через запятую в угловых скобрах.
{
op1;
op2;
}; # <--- Контроль типа возврата не производится
{
op1;
op2; # <--- Проверка типа возвращаемого значения
} :Type; # <--- Разрешенный тип
{
op1;
op2;
...
}: <:Type1, :Type2, :Type3>; # <--- Несколько разрешенных типов возврата
{
op1;
op2;
...
}: < ... >; # <--- Разрешен любой тип возвращаемого значения
Расширенный синтаксис
Расширенный синтаксис с нативным исходным кодом на языке реализации (С++), это тоже блок кода. Он начинается и заканчивается на фигурные скобки со знаком процента («{%» и «%}»).
Внутри блока кода с расширенным синтаксисом можно применять произвольные элементы языка реализации (С++), но нужно иметь ввиду, что расширенный синтаксис является исходным текстом программы и напрямую подстваляется и выходной текст трансплайтера во время компиляции файла.
С помощью блока кода с расширенным синтаксисом можно реализовать разные элементы, которые отсуствуют в основном синтаксисе, например, безусловный переход на заданную метку.
@@ label $name @@ ::= @@@ {% @$name:; %} @@@;
@@ goto $label @@ ::= @@@ {% goto @$label; %} @@@;
@goto label_for_goto;
# Skip this code
@label label_for_goto;
Взаимодействие расширенного синтаксиса с основным кодом программы происходит путем обращения к локальным объектам или макросам программы изнутри блока кода. Но для этого, имя объекта должно быть указано полностью, включая все квалификаторы имени.
Если есть необходимость обратится к статическому объекту, его имя нужно заменить макросом, так как символ двоеточия используется в синтаксисе языков C/C++.
Начиная с версии C++26 взаимодействие с расширенным синтаксисом может быть нарушено!
Add the same characters @, $, and ` to the basic character set [C++26] P2558R2
factorial := 1000;
::result := 1\1; /* Rational number */
@@ res @@ ::= ::result;
{%
// Source on the C++
for( int i=2; i <= static_cast<unsigned int>( $factorial ); i++ ){
@res *= i;
}
printf("\nFactorial %i! = %s\n",
static_cast<unsigned int>( $factorial ),
static_cast<const char *>( @res ));
# std::cout << "Factorial " << static_cast<unsigned int>( $factorial );
# std::cout << "! = " << static_cast<const char *>( @res ) << std::endl;
%}