# Контроль выполнения: условия, функции и обработка ошибок
В этом разделе описаны основные конструкции управления выполнением кода в JEXL: условные операторы, циклы, методы и функции, обработка ошибок. Материал содержит синтаксис и практические примеры для каждого элемента.

## Условные конструкции и циклы
### Условия  if-else

Синтаксис:
```
if (условие) {
    // блок кода при true
} else {
    // блок кода при false
}
```
Пример:
```
if (order.total > 10000) {
    discount = 0.1;
} else if (order.total > 5000) {
    discount = 0.05;
} else {
    discount = 0;
}
```
### Тернарный оператор

Синтаксис:
```
условие ? значение_если_true : значение_если_false
```
Пример:
```
// Простой пример
var access = (id >= 18) ? "Разрешено" : "Запрещено";
```
### Циклы

#### While

Синтаксис:
```
while (условие) {
    // действие
}
```
Пример:
```
// Простой пример
var i = 0;
while (i < 10) {
    total++;
    i++;
}
```
#### For

При использовании циклов важно понимать область видимости переменных:
- Если итерируемая переменная объявлена с `let` или `const` - она доступна только внутри блока цикла.
- Если переменная объявлена без ключевого слова (неявно) - она ведёт себя как var:
  - Доступна после выполнения цикла.
  - Сохраняет последнее присвоенное значение.
  - Если переменная с таким именем уже существовала, то переменная созданная в цикле затрет значение ранее объявленной переменной.

**Способ 1:**  
Классический C-подобный цикл с индексом.

Синтаксис:
```
for (инициализация; условие; шаг) {
    // тело цикла
}
```
Пример:
```
let x = 0;
for (let i = 0; i < 10; ++i) {
    x += i
}
dialogs.showMessage(toString(x));
```
Подходит также для массивоподобных структур, где есть доступ по индексу `(array[i])`:
```
let x = 0;
let array = [100, 200, 300];
for (let i = 0; i < size(array); ++i) {
    x += array[i];
}
```
Позволяет гибко управлять индексом коллекции (например, менять шаг i += 2).

**Способ 2:**

Синтаксис:
```
for (let элемент : коллекция) {
    // тело цикла
    // элемент доступен только здесь
}
```
Используется для перебора элементов итерируемой структуры (массива, коллекции и т. д.). Итерируемая переменная получает значение каждого элемента на каждой итерации.
```
let x = 0;
let array = [1, 2, 3];
for (let item : array) {
    x += item;
}
```
Переменная item доступна только внутри цикла (если используется `let`).

**Способ 3:**

Синтаксис:
```
for (элемент : коллекция) {
    // тело цикла
    // элемент доступен здесь
}
// элемент ДОСТУПЕН и здесь (ведёт себя как var)
```
Если итерируемую переменную не объявлять никаким ключевым словом(`let`, `const`, `var`), то она будет объявлена как `var`, и будет иметь последнее присвоенное значение.

Пример коллекции:
```
let x = 0;
let array = [1, 2, 3];
for (item : array) {
    x += item;
}
dialogs.showMessage(toString(item)); // Будет выведено значение '3'
```
- item не объявляется явно — она создаётся неявно и "живёт" после цикла.
- Может привести к неожиданным эффектам, если item уже была определена ранее.
- Обход результатов объектного запроса с преобразованием в список.
  ```
  var l= toJRops(Btk_SomeEntityApi.byParent(rop)).asList()
  for(r:l){
      logInfo(r.id);
      logInfo(r.sSystemName)
  }
  ```
Пример множества:
```
var mvStock = {"P-1001", "P-1002", "P-1003"};
for(item : mvStock) {
    dialogs.showMessage(item);
}
```
Пример карты:
```
var mvStock = {"P-1001" : 1, "P-1002" : 2, "P-1003" : 3};
for(item : mvStock) {
    dialogs.showMessage(item); // Здесь item это значения словаря по ключу
}
```
#### Foreach

Синтаксис:
```
коллекция.foreach(элемент -> {
    // действия с элементом
});
```
В JEXL оператор `foreach` используется исключительно для функционального подхода, когда данные поступают в виде потока (например, из SQL-запроса или коллекции).

Ключевые особенности:
- потоковая обработка;
- нет возвращаемого значения.

Пример:
```
sql("SELECT name FROM users").foreach(row -> {
    logInfo("User: " + row.name);
});
```
## Вызов методов и функций в JEXL

### Базовый вызов методов

Синтаксис:
```
объект.метод(параметры)
```
Пример:
```
dialogs.showMessage(ropvInvoice);
dialogs.showMessage(toString(ropvInvoice.nsum));
```
Поддерживается цепочка вызовов:
```
sheet.getRow(0).getCell(1)
```
### Определение пользовательской функции

Синтаксис:
```
function имяФункции(параметры) {
    // тело функции
    результат; // опционально
}
```
Пример:
```
function calculateSum(a, b) {
    // Тело функции
    a + b; // Возвращаемый результат (неявный return)
}

dialogs.showMessage(toString(calculateSum(2, 3)));
```
### Объявление локальных функций

Синтаксис:
```
var fun_LoadInvoiceTemplate = function(x) {
    // Тело функции
    return true;
};
```
Пример:
```
function test(params) {
    dialogs.showMessage("hello world");
}

const FX_DeleteInvisibleSymbolsF = function(sText) {
    var querry = sql(`Select regexp_replace('${sText}', '[\\s\\u200B\\u200C\\u200D\\uFEFF]', '', 'g') as ShortText;`).asSingle();
    return querry.shorttext;
}

//--------------------------------------------------------------------------
//main code block
//--------------------------------------------------------------------------
{
    var sCaptionLong = 'А 694 ЕМ 147_2024 12 105'
    var sCaptionFunc = FX_DeleteInvisibleSymbolsF(sCaptionLong);
    dialogs.showMessage('FUNC: '+ sCaptionFunc);
}

const FX_DeleteInvisibleSymbolsF = function(sText) {
    var querry = sql(`
        SELECT regexp_replace('${sText}', '[\\s\\u200B\\u200C\\u200D\\uFEFF]', '', 'g') AS ShortText;
    `).asSingle();
    return querry.shorttext;
}

//--------------------------------------------------------------------------
// Main code block
//--------------------------------------------------------------------------
{
    var sCaptionLong = 'А 694 ЕМ 147_2024 12 105';
    var sCaptionFunc = FX_DeleteInvisibleSymbolsF(sCaptionLong);
    dialogs.showMessage('FUNC: ' + sCaptionFunc);
}
```
## Обработка ошибок

Jexl в ядре не поддерживает исключения, механизм исключений реализован через аннотации.

Синтаксис:
```
@begin{
    //code
}@exception function(e){
    // code
}
```
Для бросания исключения можно воспользоваться командой raise: `raise("Текст исключения")`

```{attention}
Конструкция `try - catch` не работает. Вместо нее обязательно необходимо использовать `@begin - @exception`.
```

Пример:
```
const ErrorHandler = new java.util.concurrent.atomic.AtomicReference(null); // Объявим обработчик ошибок

... // Произвольный блок кода

var svLogList = ''; // Переменная для лога успешности и ошибок
ErrorHandler.set(null); // Сбросим обработчик ошибок перед попыткой поймать ошибку

@begin { // Блок кода, в котором попытаемся поймать ошибку
    ... // Произвольный блок кода
    raise("Текст ошибки"); // Событие, которое вызывает ошибку
}
@exception function(vEx1) { // Обработка исключения
    ErrorHandler.set(vEx1); // Сохраняем ошибку в наш обработчик
}; // Обязательно ставим точку с запятой

const ErrorCatch = ErrorHandler.get(); // Запросим значение из обработчика

if (isNotNull(ErrorCatch)) { // Проверяем, была ли ошибка
    svLogList += `\r\n - Ошибка! ${ErrorCatch.getCause().getMessage()}`;
} else {
    svLogList += `\r\n - Успешно!`;
}

dialogs.showMessage(svLogList); // Отображение логов на экране
```
### Ограничения именованных параметров

В JEXL синтаксис именованных параметров `method(paramName = value)` **не работает**. 

Неверно:
`Act_TransDocApi.createBySrc(gidpSrc = aroDoc.gid())`

Верно:
`Act_TransDocApi.createBySrc(aroDoc.gid())` — только позиционная передача аргументов в порядке сигнатуры.