Блоки кода
Блок кода, это сгруппированный набор идущих подряд инструкций, которые выполняются как единое целое с возвращением результата выполнения последней из них. Блок кода, как и любая синтаксическая конструкция языка, должен завершаться точкой с запятой “;”.
Блоки кода используются для ограничения области видимости переменных. С их помощью определяется иерархия области имен и реализуется система именования свойств и методов для классов. Именованные блоки кода могут выступать в качестве локальных меток для передачи потока выполнения.
За счет того, что к блоку кода можно обратится как к единой инструкции, они могут использоваться в других операторах. Тело функции, также представляет собой блока кода, который располагается в пространстве имен определения этой функции.
ns:: { # Пространство имен ns
name {
# Пространство имен ns::name
# В конце имени "::" можно не указывать
};
:: {
# Глобальное пространство имен
...
};
{
# Локальная переменная до завершения блока кода
$local ::= 0;
};
$local; # <-- Ошибка! Локальная переменная не видна
};
func_name(val) ::= {
# Блок кода func_name::
@if($val) {
...
} @else {
...
};
};
Оформление блока кода
Блок кода всегда начинается и заканчивается на фигурные скобки («{» и «}») и завершается точкой с запятой “;”. Существуют блоки кода, которые перехватывают потоки выполнения, с помощью которых реализуются возврат и обработка ошибок.
Тип возвращаемого значения блоком кода можно указать в явном виде. Для этого, после завершающей фигурной скобки, нужно указать разрешенный тип, после чего компилятор будет проверят корретность данных внутрие блока кода, которые могут быть возвращены.
Можно указать сразу несколько типов, перечислив их в угловых скобрах через знак + и без завершающей запятой. Если в угловых скобках перед именем типа будет стоять знак минус -, это означает, что данные тип исключен из списка разрешенных, например <:Arithmetic - :Rational - :Complex> означает любые числа, кроме рациональьных и комплексных.
{
op1;
op2;
}; # <--- Контроль типа возврата не производится
{
op1;
op2; # <--- Проверка типа возвращаемого значения
} :Type; # <--- Разрешенный только конкретный тип
{
op1;
op2;
...
}: <:Type1 + :Type2 + :Type3>; # <--- Несколько разрешенных типов возврата
{
op1;
op2;
...
}: < ... >; # <--- Разрешен любой тип возвращаемого значения
Нативный синтаксис
Нативный синтаксис, это блок кода с исходным текстом программы на языке реализации (С++). Он начинается и заканчивается на фигурные скобки со знаком процента («{%» и «%}»).
Внутри блока кода с нативный синтаксисом можно применять произвольные элементы языка реализации (С++), но нужно иметь ввиду, что нативный синтаксис является исходным текстом программы и напрямую подстваляется и выходной текст трансплайтера во время компиляции файла.
С помощью блока кода с нативным синтаксисом можно реализовать разные элементы, которые отсуствуют в языке NewLang, например, безусловный переход на заданную метку.
@@ 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;
%}