Язык программирования Перфолента.Net - Официальный сайт

 Язык программирования Перфолента.Net - Официальный сайт.

Поиск   
Главная :: О проекте :: Контакты :: Обратная связь :: Благодарности :: ВходГость

   >   >   > 


Пример «Перфо»

Файлы:

  • Перфо.пфл

Пример программы на языке программирования Перфолента.Net:



// Эта программа написана на языке программирования Перфолента.Net
// и представляет собой интерпретатор языка программирования Перфо,
// русскоязычный вариант языка похожего на Scheme,
// однако, унифицированный с языком Перфолента 
// и приспособленный для работы в среде Net. 

#ВерсияСборки "0.4.18.0"
#НазваниеПродукта "Интерпретатор языка Перфо"
#ОписаниеПродукта "Интерпретатор языка Перфо"
#ВерсияПродукта "0.4.18.0"
#Компания "Промкод"
#АвторскоеПраво "Рогаткин С.А., 2026."
#ТорговаяМарка "Перфо"

// программа написана очень быстро, поэтому вижу множество возможностей 
// для оптимизации скорости работы и уменьшения размеров кода... когда будет время оптимизирую...  

/*
  Описание языка:  
  - есть 3 типа сущностей  Идентификаторы, Значения и Списки
  
  - значениями могут быть простые типы: строки, символы, числа, даты, булево и неопределено, 
    а так же созданные во время выполнения объекты и действия
  - синтаксис значений такой же, как в языке Перфолента (поддерживаются все типы и литералы): 
    "строка" - тип Строка, "С"с - тип Символ, 4 - тип Целое, 4.537 - тип Вещ, 4.537д - тип ДВещ, 4.5ч - тип Число, 
    '23.07.2020' - тип Дата, Истина - тип Булево, Неопределено и другие (смотри в документации Перфоленты)    
  - любой другой набор символов не содержащий пробельных символов и круглых скобок является идентификатором: А1, $SYM, !!!Ошибка!!!
  - списки состоят из любых сущностей разделенных пробелами и заключенных в круглые скобки: (+ 3 4 5)
  - действие это список, первым элементом которого является идентификатор, а остальные элементы являются параметрами действия
  (ИдентификаторДействия Параметр1 Параметр2 ... ПараметрН), например, (мин 34 9 100)
  - идентификатор может быть вычисляемым ((Идент "ИдентификаторДействия") Параметр1 Параметр2 ... ПараметрН)
  - идентификатор может быть составным, например, методом/свойством/полем объекта (ИмяОбъекта.ИмяМетода Параметр1 Параметр2 ... ПараметрН)
  - параметр действия может быть любой сущностью или последовательностью
  - последовательность это список состоящий из любых сущностей, у которого первый элемент НЕ идентификатор
  (Значение1 Значение2 Значение3) или ((Действие1) (Действие2) (Действие3)) или ((Действие1) (Действие2) Значение1)
  - оператор это специальная форма действия, в которой смысл и назначение параметров, 
    а так же их последовательность выполнения определены стандартом языка,
    например, (Если (Условие) (СписокДействий1) (СписокДействий2))
    или (Перем ИмяПеременной Значение)
  Возвращаемые значения:
  - значение возвращает само себя
  - идентификатор возвращает сопоставленное ему значение, в том числе, действие, идентификатор или неопределено
  - действие может вернуть значение, другое действие, идентификатор или неопределено
  - оператор возвращает то, что определено стандартом языка
  - последовательность возвращает результат вычисления последнего элемента
  Комментарии и директивы препроцессора:
  - как и в языке Перфолента, комментарии начинаются символами //, а директивы препроцесора с символа # в начале строки
  
*/

#ТипСборки КонсольноеПриложение
#ИспользоватьСтандартнуюБиблиотеку

ИмпортИмён Промкод.Перфолента.Консоль

//***************************
&ВидноВсем
Программа Перфо

    //Стандартное окружение хранит значения и действия заданные стандартом языка.
    Поле СтандартноеОкружение тип клОкружение = ЗаполнитьСтандартноеОкружение()
    
    //Глобальное окружение хранит значения переменных и определения действий
    //в глобальном контексте выполнения программы.
    //Действие (Сброс) возвращает глобальное окружение к стандартному
    Поле ГлобальноеОкружение тип клОкружение = Новый клОкружение(СтандартноеОкружение)
    
    //оператор (Отладка Ложь) выключает вывод сообщений об ошибках в консоль
    //при выполнении скрипта запущенного из командной строки
    //если отладка выключена, то консоль просто закроется и программа вернет код ошибки окружению ОС
    Поле Отладка тип Булево = Истина 
    
    //счетчик служит для определения текущего числа вложенных циклов
    //для работы операторов Прервать и Продолжить
    Поле СчетчикВложенныхЦиклов тип Целое = 0
    //флаг устанавливаемый командой Прервать
    Поле НадоПрерватьЦикл тип Булево = Ложь
    //флаг устанавливаемый командой Продолжить
    Поле НадоПродолжитьЦикл тип Булево = Ложь
    
    //оператор Возврат помещает сюда значение
    Поле ЗначениеВозврата тип Объект = Неопределено  
    //флаг устанавливаемый командой Возврат
    Поле НадоВыполнитьВозврат тип Булево = Ложь
    
    //в этом массиве хранятся имена импортированные оператором ИмпортИмен
    Поле ИмпортыИмен тип Массив<Строка> = Новый Массив<Строка>
    
    //Истина, если программа запущена как библиотека
    Поле ЗапущенНеВКонсоли тип Булево = Ложь
    
    //стек выполнения используется для возможности указать позицию произошедшей ошибки в тексте программы
    Поле СтекВыполненияСписков тип Стек<клСписок> = Новый Стек<клСписок>
    
    //используем функцию Старт, а не процедуру, что бы вернуть операционной системе код возврата
    //---------------------------
    Функция Старт() тип Целое
    
        Если ЭтаПрограмма.КоличествоАргументовКоманднойСтроки > 0
            
            // выполняем скрипт из файла
            
            Файл = СокрЛП(ЭтаПрограмма.ПолучитьАргументКоманднойСтроки(0))
            Если ФС.ФайлСуществует(Файл) 
                Попытка
                    ТекстПрограммы = ФС.ПрочитатьТекст(Файл)  
                    Если Найти(ТекстПрограммы,"#ВключитьФайл",,Истина)>0
                        ТекстПрограммы = ВключитьФайлы(ТекстПрограммы)
                    КонецЕсли
                    Результат = Выполнить(Компилировать(ТекстПрограммы))
                Исключение Ош
                    Если Отладка
                        ВыводСтроки "Ошибка выполнения программы (код 1): "+Ош.ОписаниеОшибки+ИзвлечьПозициюОшибки() 
                        Пауза
                    КонецЕсли    
                    Возврат 1 //ошибка при выполнении программы
                КонецПопытки
            Иначе
                Если Отладка
                    ВыводСтроки "Ошибка (код 2): Не найден файл программы "+Файл 
                    Пауза
                КонецЕсли    
                Возврат 2 //ошибка: файл программы не найден
            КонецЕсли
            Если Отладка
                ПереносСтроки
                Пауза
            КонецЕсли    
            Возврат 0 //ошибок нет
            
        Иначе
        
            // интерактивная работа
        
            ВыводПС("Перфо - интерпретатор функционального языка программирования.")
            ВыводПС("Версия: "+ЭтаПрограмма.Версия)
            Цикл
                ПереносСтроки
                Вывод("Перфо> ")
                ТекстПрограммы = ПрочитатьСтроку()
                Попытка
                    Результат = Выполнить(Компилировать(ТекстПрограммы))
                    Если Результат ЭтоНе Неопределено
                        Вывод(РезультатВСтроку(Результат))
                    КонецЕсли
                Исключение Ош
                    ВыводПС("Ошибка: "+Ош.ОписаниеОшибки+ИзвлечьПозициюОшибки())
                КонецПопытки
                СтекВыполненияСписков.Очистить
            КонецЦикла
            
        КонецЕсли
        
    КонецФункции
   
    //запускает на выполнение текст программы с установкой переменной ЭтотОбъект
    //используется для запуска скрипта из других программ
    //---------------------------
    &ВидноВсем
    Функция ВыполнитьПрограмму(ТекстПрограммы тип Строка, ЗначениеПеременнойЭтотОбъект тип Объект = Неопределено) тип Строка 
        ЗапущенНеВКонсоли = Истина
        Попытка
            ГлобальноеОкружение.ДобавитьДействие("этотобъект", ЗначениеПеременнойЭтотОбъект)
            Результат = Выполнить(Компилировать(ТекстПрограммы))
            Возврат РезультатВСтроку(Результат)
        Исключение Ош
            Если Отладка
                Возврат "Ошибка: "+Ош.ОписаниеОшибки 
            КонецЕсли    
            Возврат Неопределено
        КонецПопытки
    КонецФункции 
    

#Область ФункцииКомпилятора

    //запускает на выполнение откомпилированную программу
    //---------------------------
    Функция Выполнить(СписокВыражений тип клСписок) тип Объект
        Результат = Неопределено
        Для Инд=0 По СписокВыражений.Количество-1
            Результат = Вычислить(СписокВыражений.ПоИндексу(Инд),ГлобальноеОкружение)    
        КонецЦикла
        Возврат Результат
    КонецФункции    
 
    //---------------------------
    Функция Компилировать(ТекстПрограммы тип Строка) тип Объект
        ПредставлениеПрограммы = Новый клСписок
        ПредставлениеПрограммы.ПозицияВТексте=""
        Спис = РазобратьНаТокены(ТекстПрограммы)
        Перем РезСпис тип клСписок = Неопределено
        Пока Спис.Количество > 0
            Рез=ОбработатьТокены(Спис,РезСпис)
            Если Рез ЭтоТип клСписок 
                РезСпис=Рез
            Иначе
                РезСпис=Неопределено
            КонецЕсли
            ПредставлениеПрограммы.ВКонец(Рез)
        КонецЦикла
        Возврат ПредставлениеПрограммы
    КонецФункции    
 
    //---------------------------
    Функция ВключитьФайлы(ТекстПрограммы тип Строка) тип Объект
        Пт=Новый ПостроительТекста
        Т=Новый ТекстовыйДокумент(ТекстПрограммы)
        Для Стр Из Т
            Если Найти(Стр,"#ВключитьФайл",,Истина)=1
                БылаОшибка=Ложь
                Файл=СокрЛП(Сред(Стр,14))
                Если Файл.НачинаетсяИЗаканчивается("""")
                    Файл=Файл.Сред(2,СтрДлина(Файл)-2)
                КонецЕсли    
                Если ФС.ФайлСуществует(Файл) 
                    Попытка
                        ТекстФайла = ФС.ПрочитатьТекст(Файл)  
                        Если Найти(ТекстФайла,"#ВключитьФайл",,Истина)>0
                            ТекстФайла = ВключитьФайлы(ТекстФайла)
                        КонецЕсли
                        Пт.ДобавитьСтроку(ТекстФайла)
                    Исключение
                        БылаОшибка=Истина
                    КонецПопытки
                Иначе
                    БылаОшибка=Истина
                КонецЕсли
                Если БылаОшибка
                    Если Отладка
                        ВыводСтроки "Ошибка (код 3): Не найден включаемый файл "+Файл 
                        Пауза
                    КонецЕсли    
                    Возврат 3 //ошибка: включаемый файл не найден
                КонецЕсли
            Иначе
                Пт.ДобавитьСтроку(Стр)
            КонецЕсли
        КонецЦикла
        Возврат Пт.ВСтроку
    КонецФункции    
    
    //---------------------------
    Функция РазобратьНаТокены(ТекстПрограммы тип Строка) тип клСписок
        ТекстПрограммы = ПронумероватьДействия(ТекстПрограммы) 
        ТекстПрограммы = Парсер.УдалитьКомментарииИДирективыПерфоленты(ТекстПрограммы)
        масСтроки = Парсер.ВыделитьЛитералыСимволовСтрокДатПерфоленты(ТекстПрограммы)
        //разделим на токены
        Токены = ТекстПрограммы.Заменить("("," ( ").Заменить(")"," ) ").Разделить({" ",Символы.НПП,Символы.Таб,Символы.ВК,Символы.ПС},Ложь)
        //вернем значения строк, символов и дат
        Символ14 = ""+Символ(14)
        Для Инд=0 По Токены.Количество-1
            Если Лев(Токены[Инд],1)=Символ14
                Стр = Сред(Токены[Инд],2)
                Поз = Найти(Стр,Символ14)
                Если Поз=0
                    Продолжить
                Иначе
                    Стр = Лев(Стр,Поз-1)
                    Стр2 = ОчиститьСтрокуОтНумерацииДействий(масСтроки[Целое(Стр)])
                    Токены[Инд] = СтрЗаменить(Токены[Инд],Символ14+Стр+Символ14,Стр2)
                КонецЕсли
            КонецЕсли
        КонецЦикла
        Возврат Новый клСписок(Токены)
    КонецФункции    

    //---------------------------
    Функция ОбработатьТокены(Токены тип клСписок, ПредСпис тип клСписок = Неопределено) тип Объект
        Если Токены.Количество=0 
            ВызватьИсключение "Неожиданный конец программы."
        КонецЕсли
        Токен = Токены.Извлечь(0)
        Если "(" = Токен
            Спис = Новый клСписок
            Спис.ПозицияВТексте = Токены.Извлечь(0)
            СтекВыполненияСписков.Добавить(Спис)
            Цикл 
                Если Токены.Количество=0 
                    ВызватьИсключение "Ожидается символ ). Не закрытая начальная скобка"
                КонецЕсли
                Прервать Если Токены.ПоИндексу(0) = ")"
                Спис.ВКонец(ОбработатьТокены(Токены))
            КонецЦикла
            Токены.Извлечь(0) //убираем )
            СтекВыполненияСписков.Извлечь()
            Возврат Спис
        ИначеЕсли ")" = Токен
            //это очень трудный случай для диагностики места ошибки...
            //чаще всего позицией ошибки будет показан последний список в программе,
            //хотя лишняя скобка ) возможно находится на много выше...
            //для более быстрой диагностики реального места ошибки можно посоветовать 
            //временно убрать последнюю ) скобку и запустить программу...
            //скорее всего, в этом случае интерпретатор укажет на более реальное место ошибки,
            //после исправления которой можно снова поставить временно удаленную скобку в конце программы...
            ДопТ=""
            Если ПредСпис Определено
                СтекВыполненияСписков.Добавить(ПредСпис)
                ДопТ=" Позиция последнего закрытого списка "+ИзвлечьПозициюОшибки()+"."
                СтекВыполненияСписков.Извлечь()
            КонецЕсли
            ВызватьИсключение "Неожиданный символ )."+ДопТ
        Иначе
            Возврат Атом(Токен)
        КонецЕсли
    КонецФункции    

    //---------------------------
    // Распознаёт неопределено, числа, строки, символы, булево, даты и идентификаторы
    Функция Атом(Токен тип Строка) тип Объект 
        Если НРег(Токен)="неопределено" или НРег(Токен)="_"
            //это Неопределено
            Возврат Неопределено
        КонецЕсли    
        Если Токен.НачинаетсяИЗаканчивается("""")
            //это строка
            Возврат Токен.Сред(2,СтрДлина(Токен)-2)
        КонецЕсли    
        Если СтрДлина(Токен)=4 и Токен.НачинаетсяС("""") и (Токен.ЗаканчиваетсяНа("""с") или Токен.ЗаканчиваетсяНа("""c")) //рус и англ
            //это символ
            Возврат Символ(Токен.Сред(2,1))
        КонецЕсли    
        Если Токен.НачинаетсяИЗаканчивается("'")
            Дт=''
            Если РаспознатьДату(Токен.Сред(2,СтрДлина(Токен)-2),Дт)
                //это дата
                Возврат Дт
            КонецЕсли    
        КонецЕсли    
        Бул=Ложь
        ЧисЗнач=Неопределено
        //числа записываются через точку
        Если РаспознатьЧисловоеЗначение(Токен,ЧисЗнач)
            //это числовое значение
            Возврат ЧисЗнач
        ИначеЕсли РаспознатьБулево(Токен,Бул)
            //это булево
            Возврат Бул
        КонецЕсли
        //это какой-то идентификатор
        Возврат Новый клИдентификатор(Токен)
    КонецФункции    

    //Обеспечивает возможность при возникновении ошибки указать номер строки и колонки списка
    //в котором произошла ошибка
    //---------------------------
    Функция ПронумероватьДействия(ТекстПрограммы тип Строка) тип Строка
        Пт = Новый ПостроительТекста
        Токены = ТекстПрограммы.Заменить(Символы.ВКПС,Символы.ПС).Разделить({Символы.ПС},Истина)
        Для Инд=0 По Токены.Количество-1
            Стр = Токены[Инд]
            Если Найти(Стр,"(")=0
                Пт{Стр}
            Иначе
                НомКол=1
                Токены2 = Стр.Разделить({"("},Истина)
                Для Инд2=0 По Токены2.Количество-1
                    Стр2 = Токены2[Инд2]
                    Если Инд2>0
                        Пт{"("}
                        Пт{Символ(5)}
                        Пт{Строка(Инд+1)}
                        Пт{Символ(5)}
                        Пт{Строка(НомКол)}
                        Пт{Символ(5)}
                        Пт{" "}
                        НомКол+=1
                    КонецЕсли
                    НомКол+=СтрДлина(Стр2)
                    Пт{Стр2}
                КонецЦикла
            КонецЕсли
            Пт{Символы.ПС}
        КонецЦикла
        Возврат Пт.ВСтроку
    КонецФункции    

    //Очищает строку от номеров строки и колонки.
    //То, что в строки попадают эти номера является побочным эффектом алгоритма разложения на токены
    //---------------------------
    Функция ОчиститьСтрокуОтНумерацииДействий(Стр тип Строка) тип Строка 
        Нач = "("+Символ(5)
        Кон = Символ(5)+" "
        Цикл
            Поз1=Найти(Стр,Нач)
            Возврат Стр Если Поз1 = 0
            Поз2 = СтрНайти(Стр,Кон,,Поз1)
            Возврат Стр Если Поз2 = 0
            Стр=Лев(Стр,Поз1)+Сред(Стр,Поз2+2)
        КонецЦикла
    КонецФункции    
    
    //---------------------------
    Функция ИзвлечьПозициюОшибки() тип Строка 
        Возврат "" Если СтекВыполненияСписков Это Неопределено
        Возврат "" Если СтекВыполненияСписков.Количество=0
        ТекущийСписок = СтекВыполненияСписков.Проверить
        Возврат "" Если ТекущийСписок Это Неопределено
        Стр=ТекущийСписок.ПозицияВТексте
        Возврат "" Если Стр Это Неопределено
        Стр=Сред(Стр,2,СтрДлина(Стр)-2)
        НомСтроки = Стр.Лев(Символ(5))
        НомКолонки = Стр.Прав(Символ(5))
        Возврат " (Строка "+НомСтроки+"; Колонка "+НомКолонки+")" //+РезультатВСтроку(ТекущийСписок)
    КонецФункции     

    //---------------------------
    Функция РезультатВСтроку(Результат тип Объект) тип Строка 
        Если Результат Это Неопределено
            Возврат ""
        ИначеЕсли Результат ЭтоТип клСписок Для Спис
            Стр = "("
            Для Об Из Спис.Данные
                Стр &= ?(Стр = "(",""," ")+РезультатВСтроку(Об)
            КонецЦикла
            Возврат Стр+")"
        Иначе
            Возврат Строка(Результат)
        КонецЕсли    
    КонецФункции    
    
    //тут можно определить стандартные функции и значения языка
    //все эти значения переопределяемые во время выполнения
    //---------------------------
    Функция ЗаполнитьСтандартноеОкружение() тип клОкружение
    
        Окруж = Новый клОкружение()
    
        ДОСМО = ПолучитьДелегат(,ОператорСМассивомОперандов,"ФункцияСМассивомОперандов")
        ДОСТО = ПолучитьДелегат(,ОператорСТремяОперандами,"ФункцияСТремяОперандами")
        ДОСДО = ПолучитьДелегат(,ОператорСДвумяОперандами,"ФункцияСДвумяОперандами")
        ДОСОО = ПолучитьДелегат(,ОператорСОднимОперандом,"ФункцияСОднимОперандом")
        ДОБО  = ПолучитьДелегат(,ОператорБезОперандов,"ФункцияБезОперандов")
        
        //функции с массивом операндов
        Для Имя Из {"+","-","*","/","^","**","&","или","и","бити","битили","макс","мин","стршаблон","стрнайти","знчтипа",
            "срезстроки","срезмассива","командасистемы","запуститьприложение","дэл","добавитьэлемент","сэл","сложитьэлементы"}
            Окруж.ДобавитьДействие(Имя,Новый клВстроеннаяФункция(Имя,ДОСМО))
        КонецЦикла
        
        //функции с тремя операндами
        Для Имя Из {"сред","стрзаменить","стрразделить","уэл","установитьэлемент"}
            Окруж.ДобавитьДействие(Имя,Новый клВстроеннаяФункция(Имя,ДОСТО))
        КонецЦикла
        
        //функции с двумя операндами
        Для Имя Из {"%",">","<",">=","<=","=","<>","!=","это","этоне","этотип","этонетип","исклили","битисклили","найти",
            "еслинеопределено","??","лев","прав","найтисконца","стрчисловхождений","стрполучитьстроку","стрсравнить","стрсоединить",
            "окр","добавитьмесяц","logn","atan2","знчктипу","нстр","систр","формат","стрначинаетсяс","стрзаканчиваетсяна",
            "кодсимвола","pow","пэл","получитьэлемент"}
            Окруж.ДобавитьДействие(Имя,Новый клВстроеннаяФункция(Имя,ДОСДО))
        КонецЦикла
        
        //функции с одним операндом 
        Для Имя Из {"не","целое","байт","цел8","цел16","цел32","цел64","бит8","бит16","бит32","бит64",
            "число","строка","объект","дата","булево","символ","вещ","двещ","длина",
            "неопределено?","определено?","функция?","список?","пусто?","целое?","байт?","цел8?","цел16?","цел32?","цел64?","бит8?","бит16?","бит32?","бит64?",
            "число?","строка?","объект?","дата?","булево?","символ?","вещ?","двещ?","помодулю","корень","синус","косинус","тангенс",
            "стрдлина","врег","нрег","трег","сокрл","сокрп","сокрлп","пустаястрока","пустаястрока?",
            "стрколичествострок","стрчислострок",
            "цел","дроб",
            "значениезаполнено","log","log10","sin","cos","tan","asin","acos","atan","sqrt","exp",
            "abs","абс","sign","знак","начгода","конгода","начквартала","конквартала","начмесяца","конмесяца","начнедели","коннедели",
            "началогода","конецгода","началоквартала","конецквартала","началомесяца","конецмесяца","началонедели","конецнедели",
            "начдня","кондня","наччаса","кончаса","начминуты","конминуты","началодня","конецдня","началочаса","конецчаса",
            "началоминуты","конецминуты","год","квартал","месяц","день","час","минута","секунда","деньгода","деньнедели","неделягода",
            "датагод","датаквартал","датамесяц","датачисло","номернеделигода","номерднягода","номерднянедели",
            "тип","типзнч","типзнчстр",
            "получитьимявременногофайла",
            "числоизшестнадцатеричнойстроки","числоиздвоичнойстроки",
            "целукз","битукз","этомассив","массив?"}
            Окруж.ДобавитьДействие(Имя,Новый клВстроеннаяФункция(Имя,ДОСОО))
        КонецЦикла
        
        //функции без операндов
        Для Имя Из {"текущаядата","текущаяуниверсальнаядатавмиллисекундах","текущаяуниверсальнаядата","каталогвременныхфайлов","каталогпрограммы",
            "каталогдокументов","получитьразделительпути","сигнал"}
            Окруж.ДобавитьДействие(Имя,Новый клВстроеннаяФункция(Имя,ДОБО))
        КонецЦикла
        
        //остальные константы и функции
        Окруж.ДобавитьДействие{
            {"вкпс",        Символы.ВКПС}, 
            {"вк",          Символы.ВК}, 
            {"пс",          Символы.ПС}, 
            {"пф",          Символы.ПФ}, 
            {"таб",         Символы.Таб}, 
            {"втаб",        Символы.ВТаб}, 
            {"нпп",         Символы.НПП}, 
            {"упс",         Символы.УПС}
        }
        Возврат Окруж
    КонецФункции    
    
    
    //---------------------------
    Функция Вычислить(Элемент тип Объект, Окруж тип клОкружение) тип Объект
        
        Если НадоВыполнитьВозврат
            Возврат Неопределено
        КонецЕсли
        
        Если НадоПрерватьЦикл или НадоПродолжитьЦикл
            Возврат Неопределено
        КонецЕсли    
       
        Если Элемент ЭтоТип клИдентификатор Для ТекИдентификатор 
            //получим значение переменной
            ТекОкруж = Окруж.НайтиОкружение(ТекИдентификатор)
            Если ТекОкруж Это Неопределено
                Если ТекИдентификатор.Код=-1
                    //вычисляем действие из библиотеки
                    ИД=ТекИдентификатор.ОригиналИД
                    Спец=Рефлектор.ПолучитьСпецификациюВызова(ИД)
                    Если Спец Это Неопределено
                        ВызватьИсключение "Ошибка в спецификации вызова ("+ИД+"): "+Рефлектор.ОписаниеОшибки
                    КонецЕсли
                    ТекОбъект = Неопределено
                    //получим объект
                    Если Лев(Спец.ИмяТипа,1)="@"
                        Спец.ИмяТипа=Сред(Спец.ИмяТипа,2)
                    Иначе
                        ТекОкруж = Окруж.НайтиОкружение(Спец.ИмяТипа)
                        Если ТекОкруж Определено
                            ТекОбъект = ТекОкруж.ПолучитьДействие(Спец.ИмяТипа)
                        КонецЕсли
                    КонецЕсли
                    Рез = Неопределено
                    Если НЕ Рефлектор.ПолучитьЗначение(Спец,ТекОбъект,Неопределено,Рез,ИмпортыИмен)
                        ВызватьИсключение "Ошибка при вызове ("+ИД+"): "+Рефлектор.ОписаниеОшибки
                    КонецЕсли
                    Возврат Рез
                КонецЕсли
                ВызватьИсключение "Не найден идентификатор "+ТекИдентификатор 
            Иначе
                Возврат ТекОкруж.ПолучитьДействие(ТекИдентификатор)
            КонецЕсли
        КонецЕсли
        
        Если НЕ (Элемент ЭтоТип клСписок Для Спис)       
            //если это не список, значит атом
            Возврат Элемент           
        КонецЕсли
        //это точно список
        СтекВыполненияСписков.Добавить(Спис)
        Элемент = ВычислитьСписок(Спис, Окруж)
        СтекВыполненияСписков.Извлечь()
        Возврат Элемент
    КонецФункции
    
    //---------------------------
    Функция ВычислитьСписок(Спис тип клСписок, Окруж тип клОкружение) тип Объект

        КвоЭлементов = Спис.Количество
        Если КвоЭлементов=0
            Возврат Неопределено 
        КонецЕсли
        
        //разберемся с первым элементом списка
        Перем ИД тип Строка = ""
        Рез = Спис.ПоИндексу(0)
        Если Рез ЭтоТип клСписок Для СписП
            СтекВыполненияСписков.Добавить(СписП)
            Рез = ВычислитьСписок(СписП, Окруж)
            СтекВыполненияСписков.Извлечь()
        КонецЕсли
        Если Рез ЭтоТип клВстроеннаяФункция Для ВСФЯ
            //вычисляем встроенную функцию
            ИД=ВСФЯ.Имя
            Элементы = Новый Объект[КвоЭлементов-2]
            Для Инд=1 По КвоЭлементов-1
                Элементы[Инд-1]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
            КонецЦикла
            Возврат ВыполнитьДействие(Рез, ИД, Элементы, Окруж)
        ИначеЕсли Рез ЭтоТип клФункцияПользователя Для ФЯПО
            //вычисляем функцию пользователя
            Элементы = Новый Объект[КвоЭлементов-2]
            Для Инд=1 По КвоЭлементов-1
                Элементы[Инд-1]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
            КонецЦикла
            Возврат ВыполнитьДействие(Рез, "", Элементы, Окруж)
        ИначеЕсли Рез ЭтоТип System.Delegate Для ФСД
            Элементы = Новый Объект[КвоЭлементов-2]
            Для Инд=1 По КвоЭлементов-1
                Элементы[Инд-1]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
            КонецЦикла
            Возврат ФСД.ВыполнитьДинамически(Элементы)        

        ИначеЕсли Рез ЭтоТип клИдентификатор Для ТекИдентификатор
            //будем выполнять действие по идентификатору
            ИД=ТекИдентификатор.ИД
        
        Иначе
            Рез = Вычислить(Рез, Окруж)
            Если Рез ЭтоТип клИдентификатор Для ТекИдентификатор
                //всё же действие
                ИД=ТекИдентификатор.ИД
            Иначе
                //обходим последовательность
                Для Инд=1 По КвоЭлементов-1
                    Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                КонецЦикла
                Возврат Рез
            КонецЕсли
        КонецЕсли
        
        Код = ТекИдентификатор.Код
        Если  Код > 0
            Если Код=1 // ИД = "вывод" или ИД = "сообщить"                  
                //вычисляем и выводим в консоль все элементы списка
                Для Инд=1 По КвоЭлементов-1
                    Рез = Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Прервать Если НадоВыполнитьВозврат
                    Вывод(РезультатВСтроку(Рез))
                КонецЦикла
                Возврат Неопределено
            
            ИначеЕсли Код=2 // ИД = "перем"                 
                //определяем переменную
                //например, присвоим переменной А1 значение 100: (Перем А1 100)
                //переменная сохраняется в текущее окружение
                ПроверитьЧислоОперандов(КвоЭлементов=3,ИД)
                //идентификатор переменной может вычисляться налету 
                //например, (Перем (Идент (+ "А" "1")) 100)
                ТекИдентификатор = ПолучитьИдентификатор(Спис.ПоИндексу(1), Окруж, ИД, 2)
                Зн = Вычислить(Спис.ПоИндексу(2), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Окруж.ВставитьДействие(ТекИдентификатор, Зн)
                Возврат Неопределено
            
            ИначеЕсли Код=3 // ИД = "идент"
                //вычисляет операнд и превращаем результат в идентификатор
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Возврат Новый клИдентификатор(РезультатВСтроку(Рез))
                
            ИначеЕсли Код=4 // ИД = "если"                  
                //Вычисляем условие.
                //Если условие выполнилось, то вычисляем Список1,
                //иначе, вычисляем Список2, если он есть. 
                //Возвращаем результат того списка, который вычислялся или Неопределено, когда список 2 не задан.
                //(Если (Условие) Список1)
                //(Если (Условие) Список1 Список2)
                ПроверитьЧислоОперандов(КвоЭлементов=3 или КвоЭлементов=4,ИД)
                Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Если КвоЭлементов=3
                    Возврат Вычислить(?(Булево(Рез),Спис.ПоИндексу(2),Неопределено), Окруж)
                Иначе
                    Возврат Вычислить(?(Булево(Рез),Спис.ПоИндексу(2),Спис.ПоИндексу(3)), Окруж)
                КонецЕсли;
            
            ИначеЕсли Код=5 // ИД = "продолжить"
                //установим флаг, указывающий, что надо продолжить цикл
                ПроверитьЧислоОперандов(КвоЭлементов=1,ИД)
                Если СчетчикВложенныхЦиклов=0
                    ВызватьИсключение "Оператор Продолжить использован вне цикла." 
                КонецЕсли
                НадоПродолжитьЦикл=Истина
                Возврат Неопределено
    
            ИначеЕсли Код=6 // ИД = "прервать"
                //установим флаг, указывающий, что надо прервать цикл
                ПроверитьЧислоОперандов(КвоЭлементов=1,ИД)
                Если СчетчикВложенныхЦиклов=0
                    ВызватьИсключение "Оператор Прервать использован вне цикла." 
                КонецЕсли
                НадоПрерватьЦикл=Истина
                Возврат Неопределено
    
            ИначеЕсли Код=7 // ИД = "цикл"                 
                //выполняем тело цикла пока не встретим оператор Прервть
                //(Цикл Список)
                ПроверитьЧислоОперандов(КвоЭлементов>=2,ИД)
                
                Рез=Неопределено
                Цикл
                    Для Инд=1 По КвоЭлементов-1
                        СчетчикВложенныхЦиклов+=1
                        Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                        СчетчикВложенныхЦиклов-=1
                        Если НадоПрерватьЦикл или НадоПродолжитьЦикл или НадоВыполнитьВозврат
                            Прервать
                        КонецЕсли    
                    КонецЦикла
                    Если НадоПродолжитьЦикл
                        НадоПродолжитьЦикл=Ложь
                        Продолжить
                    КонецЕсли    
                    Если НадоПрерватьЦикл
                        НадоПрерватьЦикл=Ложь
                        Прервать
                    КонецЕсли    
                    Прервать Если НадоВыполнитьВозврат
                КонецЦикла
                Возврат Неопределено
    
            ИначеЕсли Код=8 // ИД = "пока"                 
                //выполняем тело цикла пока выполняется условие
                //(Пока (Условие) Список)
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                
                Рез=Неопределено
                Пока Булево(Вычислить(Спис.ПоИндексу(1), Окруж))
                    Для Инд=2 По КвоЭлементов-1
                        СчетчикВложенныхЦиклов+=1
                        Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                        СчетчикВложенныхЦиклов-=1
                        Если НадоПрерватьЦикл или НадоПродолжитьЦикл или НадоВыполнитьВозврат
                            Прервать
                        КонецЕсли    
                    КонецЦикла
                    Если НадоПродолжитьЦикл
                        НадоПродолжитьЦикл=Ложь
                        Продолжить
                    КонецЕсли    
                    Если НадоПрерватьЦикл
                        НадоПрерватьЦикл=Ложь
                        Прервать
                    КонецЕсли    
                    Прервать Если НадоВыполнитьВозврат
                КонецЦикла
                Возврат Неопределено
            
            ИначеЕсли Код=9 // ИД = "для"                  
                //выполняем тело цикла согласно параметрам
                //(Для (ИмяПеременной От По Шаг) Список)
                //например: (Для (Инд 0 6 2) (Вывод "Инд=" Инд пс))
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                Если Спис.ПоИндексу(1) ЭтоТип клСписок Для СписП
                    КвоП=СписП.Количество
                    Если КвоП<3 или КвоП>4
                        ВызватьИсключение "Не верное число параметров цикла в операторе Для." 
                    КонецЕсли
                    ИДП = ПолучитьИдентификатор(СписП.ПоИндексу(0), Окруж, "Для. Имя переменной", 1)
                    ЗнОт = Вычислить(СписП.ПоИндексу(1), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Окруж.ВставитьДействие(ИДП, ЗнОт)
                    ЗнПо = Вычислить(СписП.ПоИндексу(2), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Если КвоП = 4
                        ЗнШаг = Вычислить(СписП.ПоИндексу(3), Окруж)
                        Возврат Неопределено Если НадоВыполнитьВозврат
                    Иначе
                        ЗнШаг = 1
                    КонецЕсли
                    Рез=Неопределено
                    Для ИндО = ЗнОт По ЗнПо Шаг ЗнШаг
                        Окруж.ВставитьДействие(ИДП, ИндО)
                        Для Инд=2 По КвоЭлементов-1
                            СчетчикВложенныхЦиклов+=1
                            Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                            СчетчикВложенныхЦиклов-=1
                            Если НадоПрерватьЦикл или НадоПродолжитьЦикл или НадоВыполнитьВозврат
                                Прервать
                            КонецЕсли    
                        КонецЦикла
                        Если НадоПродолжитьЦикл
                            НадоПродолжитьЦикл=Ложь
                            Продолжить
                        КонецЕсли    
                        Если НадоПрерватьЦикл
                            НадоПрерватьЦикл=Ложь
                            Прервать
                        КонецЕсли    
                        Прервать Если НадоВыполнитьВозврат
                    КонецЦикла
                Иначе
                    ВызватьИсключение "Второй операнд в операторе Для не является списком." 
                КонецЕсли
                Возврат Неопределено
            
            ИначеЕсли Код=10 // ИД = "длякаждого"                  
                //выполняем тело цикла согласно параметрам
                //(ДляКаждого (ИмяПеременной Коллекция) Список)
                //например: (ДляКаждого (Симв "АБВГД") (Вывод "Симв = " Симв "; " пс))
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                Если Спис.ПоИндексу(1) ЭтоТип клСписок Для СписП
                    КвоП=СписП.Количество
                    Если КвоП<>2
                        ВызватьИсключение "Не верное число параметров цикла в операторе ДляКаждого." 
                    КонецЕсли
                    ИДП = ПолучитьИдентификатор(СписП.ПоИндексу(0), Окруж, "ДляКаждого. Имя переменной", 1)
                    КоллО = Вычислить(СписП.ПоИндексу(1), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Рез=Неопределено
                    Для Об тип Объект Из КоллО КАК ИПеречисляемый 
                        Окруж.ВставитьДействие(ИДП, Об)
                        Для Инд=2 По КвоЭлементов-1
                            СчетчикВложенныхЦиклов+=1
                            Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                            СчетчикВложенныхЦиклов-=1
                            Если НадоПрерватьЦикл или НадоПродолжитьЦикл или НадоВыполнитьВозврат
                                Прервать
                            КонецЕсли    
                        КонецЦикла
                        Если НадоПродолжитьЦикл
                            НадоПродолжитьЦикл=Ложь
                            Продолжить
                        КонецЕсли    
                        Если НадоПрерватьЦикл
                            НадоПрерватьЦикл=Ложь
                            Прервать
                        КонецЕсли    
                        Прервать Если НадоВыполнитьВозврат
                    КонецЦикла
                Иначе
                    ВызватьИсключение "Второй операнд в операторе ДляКаждого не является списком." 
                КонецЕсли
                Возврат Неопределено
            
            ИначеЕсли Код=11 // ИД = "попытка"                 
                //перехватываем ошибку в списке 1
                //обрабатываем ошибку в списке 2
                //завершение делаем в списке 3
                //(Попытка Список1 Список2 Список3)
                //например: (попытка (/ 5 0) (вывод "Ошибка" пс) (вывод "завершение"))
                ПроверитьЧислоОперандов(КвоЭлементов>1 и КвоЭлементов<=4,ИД)
                Попытка
                    Рез=Вычислить(Спис.ПоИндексу(1), Окруж)
                    //ВыводСтроки Рез
                Исключение Ош
                    Окруж.ВставитьДействие("Ошибка",Ош)
                    Окруж.ВставитьДействие("ОписаниеОшибки",Ош.ОписаниеОшибки)
                    Если КвоЭлементов>2
                        Рез=Вычислить(Спис.ПоИндексу(2), Окруж)
                    КонецЕсли
                Завершение
                    Окруж.ВставитьДействие("Ошибка",Неопределено)
                    Окруж.ВставитьДействие("ОписаниеОшибки",Неопределено)
                    Если КвоЭлементов=4
                        Рез=Вычислить(Спис.ПоИндексу(3), Окруж)
                    КонецЕсли
                КонецПопытки
                Возврат Неопределено
    
            ИначеЕсли Код=12 // ИД = "новый"                 
                //создать новый объект .Net из загруженных сборок 
                //пространство имён Промкод.Перфолента импортировано по умолчанию
                //например, (Новый Массив) или (Новый Структура "Вид,Количество", "Простой", 5)
                ПроверитьЧислоОперандов(КвоЭлементов>=2,ИД)
                //идентификатор типа объекта может вычисляться налету 
                //например, (Новый (Идент (+ "Мас" "сив")))
                ТекИдентификатор = ПолучитьИдентификатор(Спис.ПоИндексу(1), Окруж, ИД, 2)
                ИД=ТекИдентификатор.ОригиналИД
                Если СтрЗаканчиваетсяНа(ТекИдентификатор.ИД,".конструктор")
                    ИД=Лев(ИД,СтрДлина(ИД)-12)
                КонецЕсли
                ТипОбъекта = Рефлектор.НайтиТип(ИД,ИмпортыИмен)
                Массив Парамс[КвоЭлементов-3] тип Объект
                Для Инд=2 По КвоЭлементов-1
                    Парамс[Инд-2]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Прервать Если НадоВыполнитьВозврат
                КонецЦикла
                Возврат Неопределено Если НадоВыполнитьВозврат
                Рез = Неопределено
                Если НЕ Рефлектор.СоздатьОбъект(ТипОбъекта,Парамс,Рез)
                    ВызватьИсключение "Ошибка при вызове (Новый): "+Рефлектор.ОписаниеОшибки
                КонецЕсли
                Возврат Рез
            
            ИначеЕсли Код=13 // ИД = "++" или ИД = "--"
                //увеличиваем значение переменной на 1
                //(++ А1)
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                //идентификатор переменной может вычисляться налету 
                ТекИдентификатор = ПолучитьИдентификатор(Спис.ПоИндексу(1), Окруж, ИД, 2)
                Зн = Вычислить(ТекИдентификатор, Окруж)+?(ИД="++",1,-1)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Окруж.ВставитьДействие(ТекИдентификатор, Зн)
                Возврат Зн
    
            ИначеЕсли Код=14 // ИД = "окружение"                 
                //создаем новое окружение
                //переменные и функции созданные внутри окружения не будут видны снаружи
                //например, присвоим значения переменным Пер1 и Пер2 и выведем их сумму: 
                //(Окружение (Перем Пер1 100)(Перем Пер2 200)(Вывод (+ Пер1 Пер2)))
                ОкружФункции = Новый клОкружение(Окруж)
                Рез=Неопределено
                Для Инд=1 По КвоЭлементов-1
                    Рез=Вычислить(Спис.ПоИндексу(Инд), ОкружФункции)
                    Прервать Если НадоВыполнитьВозврат
                КонецЦикла
                Возврат Неопределено Если НадоВыполнитьВозврат
                Возврат Рез
            
            ИначеЕсли Код=15 // ИД = "функ"                  
                //определение анонимной функции (Функ (ИдентификаторыПараметров...) ТелоФункции)
                //анонимная функция получает текущее окружение
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                Если Спис.ПоИндексу(1) ЭтоТип клСписок Для СписП
                    СписокИдентификаторовПараметров = Новый клСписок
                    СписокИдентификаторовПараметров.ПозицияВТексте=Спис.ПозицияВТексте
                    Для Инд=0 По СписП.Количество-1
                        ТекИдентификатор = ПолучитьИдентификатор(СписП.ПоИндексу(Инд), Окруж, "Функ. Имя параметра № "+(Инд+1), 2)
                        СписокИдентификаторовПараметров.ВКонец(ТекИдентификатор)
                    КонецЦикла
                    Если НЕ (КвоЭлементов=3 и Спис.ПоИндексу(2) ЭтоТип клСписок Для ТелоФункции)
                        ТелоФункции = Новый клСписок
                        ТелоФункции.ПозицияВТексте=Спис.ПозицияВТексте
                        Для Инд=2 По КвоЭлементов-1
                            ТелоФункции.ВКонец(Спис.ПоИндексу(Инд))
                        КонецЦикла
                    КонецЕсли
                    Возврат Новый клФункцияПользователя(СписокИдентификаторовПараметров,ТелоФункции,Окруж)
                Иначе
                    ВызватьИсключение "Второй операнд в операторе Функция не является списком параметров." 
                КонецЕсли
            
            ИначеЕсли Код=16 // ИД = "функция"                  
                //определение функции (Функция (ИмяФункции ИдентификаторыПараметров...) ТелоФункции)
                //функция получает текущее окружение
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                Если Спис.ПоИндексу(1) ЭтоТип клСписок Для СписП
                    Перем ИДФункции тип клИдентификатор = Неопределено
                    СписокИдентификаторовПараметров = Новый клСписок
                    СписокИдентификаторовПараметров.ПозицияВТексте=Спис.ПозицияВТексте
                    Для Инд=0 По СписП.Количество-1
                        ТекИдентификатор = ПолучитьИдентификатор(СписП.ПоИндексу(Инд), Окруж, "Функция. Имя параметра № "+(Инд+1), 2)
                        Если Инд=0
                            ИДФункции = ТекИдентификатор
                        Иначе
                            СписокИдентификаторовПараметров.ВКонец(ТекИдентификатор)
                        КонецЕсли
                    КонецЦикла
                    Если ИДФункции = Неопределено
                        ВызватьИсключение "Имя функции неопределено." 
                    КонецЕсли
                    Если НЕ (КвоЭлементов=3 и Спис.ПоИндексу(2) ЭтоТип клСписок Для ТелоФункции)
                        ТелоФункции = Новый клСписок
                        ТелоФункции.ПозицияВТексте=Спис.ПозицияВТексте
                        Для Инд=2 По КвоЭлементов-1
                            ТелоФункции.ВКонец(Спис.ПоИндексу(Инд))
                        КонецЦикла
                    КонецЕсли
                    ФункП = Новый клФункцияПользователя(СписокИдентификаторовПараметров,ТелоФункции,Окруж)
                    Окруж.ВставитьДействие(ИДФункции, ФункП)
                    Возврат Неопределено
                Иначе
                    ВызватьИсключение "Второй операнд в операторе Функция не является списком параметров." 
                КонецЕсли
            
            ИначеЕсли Код=17 // ИД = "импортимен" или ИД = "импортимён"
                // импорт имен позволяет записывать типы без указания пространства имен
                // (ИмпортИмён System.Collections)
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                ТекИдентификатор = ПолучитьИдентификатор(Спис.ПоИндексу(1), Окруж, ИД, 2)
                ИмпортыИмен.Добавить(ТекИдентификатор.ОригиналИД)       
                Возврат Неопределено
    
            ИначеЕсли Код=18 // ИД = "загрузитьсборку"
                // оператор ЗагрузитьСборку позволяет использовать внешние DLL или EXE библиотеки
                // (ЗагрузитьСборку "ПутьКФайлуСборки") - для загрузки из файла
                // (ЗагрузитьСборку "ПолноеИмяСборки") - для загрузки из глобального кэша сборок,
                // например:
                // (ЗагрузитьСборку "System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                Если НЕ Рефлектор.ЗагрузитьСборку(Строка(Спис.ПоИндексу(1)))
                    ВызватьИсключение Рефлектор.ОписаниеОшибки
                КонецЕсли
                Возврат Неопределено
    
            ИначеЕсли Код=19 // ИД = "массив" 
                // создает массив
                // (Массив ВерхнийИндекс ТипЭлементов), например, (Массив 5 Целое)
                // массив можно сразу заполнить элементами
                // (Массив ВерхнийИндекс ТипЭлементов Значение0 Значение1 ... ЗначениеВИ), например, (Массив 3 Целое 1 2 3 4)
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                ВерхИнд=Целое(Рез)
                Рез = Спис.ПоИндексу(2)
                ТекИдентификатор = ПолучитьИдентификатор(Рез, Окруж, ИД, 3)
                ТипОбъекта = Рефлектор.НайтиТип(ТекИдентификатор.ОригиналИД, ИмпортыИмен)
                СисМас = System.Array.CreateInstance(ТипОбъекта, ВерхИнд+1)
                Если КвоЭлементов>3
                    Для Инд=3 По КвоЭлементов-1
                        Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                        Прервать Если НадоВыполнитьВозврат
                        СисМас.SetValue(Рез,Инд-3)
                    КонецЦикла
                    Возврат Неопределено Если НадоВыполнитьВозврат
                КонецЕсли
                Возврат СисМас
    
            ИначеЕсли Код=20 // ИД = "пауза"
                //выводим в консоль сообщение и ждем нажатия любой клавиши
                ПроверитьЧислоОперандов(КвоЭлементов=1,ИД)
                Пауза
                Возврат Неопределено
            
            ИначеЕсли Код=21 // ИД = "очистить"
                //очищаем экран консоли
                ПроверитьЧислоОперандов(КвоЭлементов=1,ИД)
                Очистить
                Возврат Неопределено
            
            ИначеЕсли Код=22 // ИД = "отладка"
                //включаем/выключаем режим отладки скрипта
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                Отладка=Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Возврат Булево(Отладка)
            
            ИначеЕсли Код=23 // ИД = "ввод"                 
                //вычисляем и выводим в консоль все приглашения
                //и ждем ввода строки в консоль и нажатия клавиши Ввод (Enter)
                Для Инд=1 По КвоЭлементов-1
                    Рез = Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Вывод(РезультатВСтроку(Рез))
                КонецЦикла
                Возврат ПрочитатьСтроку()
            
            ИначеЕсли Код=24 // ИД = "список"                 
                //заполняем и возвращаем список
                //(Список 1 2 3 4 5)
                НовСпис=Новый клСписок
                НовСпис.ПозицияВТексте=Спис.ПозицияВТексте
                Для Инд=1 По КвоЭлементов-1
                    Рез = Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    НовСпис.ВКонец(Рез)
                КонецЦикла
                Возврат НовСпис
            
             ИначеЕсли Код=25 // ИД = "оэл" или ИД = "остальныеэлементы"                  
                //возвращаем остальные элементы списка
                //(ОЭЛ (Список 1 2 3 4 5)) -  кроме первого
                //(ОЭЛ (Список 1 2 3 4 5) Кво) - кроме указанного количества 
                //если Кво больше количества элементов в списке, то вернется пустой список
                ПроверитьЧислоОперандов(КвоЭлементов=2 или КвоЭлементов=3,ИД)
                Рез=Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Если Рез ЭтоТип клСписок Для СписП
                    КвоП=СписП.Количество
                    Если КвоП=0
                        Возврат Неопределено
                    ИначеЕсли КвоЭлементов=3
                        Рез = Вычислить(Спис.ПоИндексу(2), Окруж)
                        Возврат Неопределено Если НадоВыполнитьВозврат
                        Возврат СписП.БезПервогоЭлемента(Рез)
                    Иначе
                        Возврат СписП.БезПервогоЭлемента
                    КонецЕсли
                КонецЕсли
                ВызватьИсключение "Второй операнд в операторе ОЭЛ не является списком." 
            
             ИначеЕсли Код=26 // ИД = "кромепервого"                  
                //возвращаем все элементы списка кроме первого
                //(КромеПервого (Список 1 2 3 4 5))
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                Рез=Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Если Рез ЭтоТип клСписок Для СписП
                    КвоП=СписП.Количество
                    Если КвоП=0
                        Возврат Неопределено
                    Иначе
                        Возврат СписП.БезПервогоЭлемента
                    КонецЕсли
                КонецЕсли
                ВызватьИсключение "Второй операнд в операторе КромеПервого не является списком." 
            
             ИначеЕсли Код=27 // ИД = "кромепервых"                  
                //возвращаем остальные элементы списка кроме указанного количества первых
                //(КромеПервых (Список 1 2 3 4 5) Кво) - кроме указанного количества первых элементов 
                //если Кво больше количества элементов в списке, то вернется пустой список
                ПроверитьЧислоОперандов(КвоЭлементов=3,ИД)
                Рез=Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Если Рез ЭтоТип клСписок Для СписП
                    КвоП=СписП.Количество
                    Если КвоП=0
                        Возврат Неопределено
                    Иначе
                        Рез = Вычислить(Спис.ПоИндексу(2), Окруж)
                        Возврат Неопределено Если НадоВыполнитьВозврат
                        Возврат СписП.БезПервогоЭлемента(Рез)
                    КонецЕсли
                КонецЕсли
                ВызватьИсключение "Второй операнд в операторе КромеПервых не является списком." 
            
            ИначеЕсли Код=28 // ИД = "повсем"                 
                //выполняет функцию с заданным списком аргументов  (ПоВсем (функ (х н я) (+ х н я)) 4 5 6)
                //если какой-либо аргумент является списком (или коллекцией), то список разворачивается
                //(ПоВсем функция аргументы...)
                ПроверитьЧислоОперандов(КвоЭлементов>2,ИД)
                НовСпис=Новый клСписок
                НовСпис.ПозицияВТексте=Спис.ПозицияВТексте
                Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                НовСпис.ВКонец(Рез)
                Для Инд=2 По КвоЭлементов-1
                    Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Если Рез ЭтоТип клСписок Для СписП
                        КвоП=СписП.Количество
                        Для ИндП=0 По КвоП-1
                            Рез=Вычислить(СписП.ПоИндексу(ИндП), Окруж)
                            Возврат Неопределено Если НадоВыполнитьВозврат
                            НовСпис.ВКонец(Рез)
                        КонецЦикла
                    ИначеЕсли Рез ЭтоТип ИПеречисляемый Для КоллП
                        Для Об тип Объект Из КоллП
                            НовСпис.ВКонец(Об)
                        КонецЦикла
                    Иначе
                        НовСпис.ВКонец(Рез)
                    КонецЕсли
                КонецЦикла
                Возврат ВычислитьСписок(НовСпис, Окруж)
            
            ИначеЕсли Код=29 // ИД = "покаждому"                 
                //(ПоКаждому функция аргумент1 ... аргументН), где аргумент это значение, список или коллекция
                //Выполняет функцию для каждого набора элементов собранного из заданных аргументов
                //Если вместо списка задано значение, то оно считается первым элементом списка по умолчанию.
                //(ПоКаждому (функ (х)(+ х х)) (Список 4 5 6))
                ПроверитьЧислоОперандов(КвоЭлементов>2,ИД)
                Действие = Вычислить(Спис.ПоИндексу(1), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                масСп = Новый Объект[КвоЭлементов-3]
                Для Инд=2 По КвоЭлементов-1
                    Рез=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Если Рез ЭтоТип клСписок Для СписП
                        масСп[Инд-2]=СписП
                    ИначеЕсли Рез ЭтоТип ИПеречисляемый Для КоллП
                        масСп[Инд-2]=КоллП.ПолучитьПеречислитель
                    Иначе
                        масСп[Инд-2]=Рез
                    КонецЕсли
                КонецЦикла
                НовСпис=Новый клСписок
                НовСпис.ПозицияВТексте=Спис.ПозицияВТексте
                ЭлИнд=0
                Цикл
                    ЭтоКонец=Ложь
                    Элементы = Новый Объект[КвоЭлементов-3]
                    Для Инд=0 По КвоЭлементов-3
                        ТекСпис = масСп[Инд]
                        Если ТекСпис ЭтоТип клСписок Для СписП
                            Если СписП.Количество = ЭлИнд
                                ЭтоКонец=Истина
                                Прервать
                            КонецЕсли    
                            Элементы[Инд]=Вычислить(СписП.ПоИндексу(ЭлИнд), Окруж)
                            Возврат Неопределено Если НадоВыполнитьВозврат
                        ИначеЕсли ТекСпис ЭтоТип ИПеречислитель Для Перчис
                            Если НЕ Перчис.Следующий
                                ЭтоКонец=Истина
                                Прервать
                            КонецЕсли    
                            Элементы[Инд]=Вычислить(Перчис.Текущий, Окруж)
                            Возврат Неопределено Если НадоВыполнитьВозврат
                        Иначе
                            Если ЭлИнд > 0
                                ЭтоКонец=Истина
                                Прервать
                            КонецЕсли    
                            Элементы[Инд]=Вычислить(ТекСпис, Окруж)
                            Возврат Неопределено Если НадоВыполнитьВозврат
                        КонецЕсли
                    КонецЦикла
                    Прервать Если ЭтоКонец 
                    НовСпис.ВКонец(ВыполнитьДействие(Действие, "", Элементы, Окруж)) 
                    ЭлИнд++
                КонецЦикла
                Возврат НовСпис
            
            ИначеЕсли Код=30 // ИД = "пуск" 
                // оператор Пуск позволяет запустить команду ОС
                // (Пуск Команда Аргумент1 ... АргументН), например, (Пуск "Net" "View") или (Пуск "cmd" "/c ping promcod.com.ua")
                // Ожидает возврат из запущенного процесса и возвращает код возврата.
                ПроверитьЧислоОперандов(КвоЭлементов>1,ИД)
                СтрПарам=""
                Для Инд=2 По КвоЭлементов-1
                    Рез = Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    СтрПарам &= РезультатВСтроку(Рез) + " "
                КонецЦикла
                Если ЗапущенНеВКонсоли 
                    Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Перем КодВ тип Целое
                    КомандаСистемы(РезультатВСтроку(Рез) + " " + СтрПарам,Истина,КодВ) 
                    Возврат КодВ
                Иначе
                    Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Возврат Пуск(РезультатВСтроку(Рез), СтрПарам)
                КонецЕсли
                
            ИначеЕсли Код=31 // ИД = "уст"                 
                //устанавливаем значение переменной или полю/свойству объекта
                //например, присвоим переменной А1 значение 100: (Уст А1 100)
                //присвоим значение свойству Заголовок: (Уст Консоль.Заголовок "Перфо")
                //возможно задавать объект и имя метода списком: (Уст . Консоль Заголовок "Перфо")
                ПроверитьЧислоОперандов(КвоЭлементов>=3,ИД)
                //идентификатор переменной может вычисляться налету 
                //например, (Уст (Идент (+ "А" "1")) 100)
                ТекИдентификатор = ПолучитьИдентификатор(Спис.ПоИндексу(1), Окруж, ИД, 2)
                ТекОкруж = Окруж.НайтиОкружение(ТекИдентификатор)
                Если ТекОкруж ЭтоНе Неопределено
                    Зн = Вычислить(Спис.ПоИндексу(2), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    ТекОкруж.ВставитьДействие(ТекИдентификатор, Зн)
                Иначе
                    ИД=ТекИдентификатор.ОригиналИД
                    Если Найти(ИД,".")>0
                        Спец=Рефлектор.ПолучитьСпецификациюВызова(ИД)
                        Если Спец Это Неопределено
                            ВызватьИсключение "Ошибка в спецификации вызова ("+ИД+"): "+Рефлектор.ОписаниеОшибки
                        КонецЕсли
                        ТекОбъект = Неопределено
                        Инкр=0
                        Если ИД="." 
                            //третий параметр это вычисляемый идентификатор типа или объект, 
                            //а четвертый параметр это вычисляемый идентификатор члена
                            Рез = Спис.ПоИндексу(2)
                            Если Рез ЭтоТип клИдентификатор Для ТекИдентификатор и ТекИдентификатор.Код <> -1
                                Спец.ИмяТипа = ТекИдентификатор.ОригиналИД
                            Иначе
                                Рез = Вычислить(Рез,Окруж)
                                Возврат Неопределено Если НадоВыполнитьВозврат
                                Если Рез ЭтоТип клИдентификатор Для ТекИдентификатор
                                    Спец.ИмяТипа = ТекИдентификатор.ОригиналИД
                                Иначе
                                    ТекОбъект = Рез
                                КонецЕсли
                            КонецЕсли
                            Спец.ИмяЧлена = ПолучитьИдентификатор(Спис.ПоИндексу(3), Окруж, ИД, 3)
                            Инкр=2
                        КонецЕсли
                        Если ТекОбъект Это Неопределено
                            //получим объект
                            Если Лев(Спец.ИмяТипа,1)="@"
                                Спец.ИмяТипа=Сред(Спец.ИмяТипа,2)
                                ТекОбъект = Неопределено
                            Иначе
                                ТекОкруж = Окруж.НайтиОкружение(Спец.ИмяТипа)
                                Если ТекОкруж Это Неопределено
                                    //возможно это статический вызов
                                    ТекОбъект = Неопределено
                                Иначе
                                    ТекОбъект = ТекОкруж.ПолучитьДействие(Спец.ИмяТипа)
                                КонецЕсли
                            КонецЕсли
                        КонецЕсли
                        //вычислим аргументы метода
                        Зн = Вычислить(Спис.ПоИндексу(2+Инкр), Окруж)
                        Возврат Неопределено Если НадоВыполнитьВозврат
                        Массив Элементы4[КвоЭлементов-4-Инкр] тип Объект
                        Если КвоЭлементов=3+Инкр
                            Элементы4=Неопределено
                        Иначе
                            Для Инд=2+Инкр По КвоЭлементов-1
                                Если Инд = 2+Инкр
                                    Элементы4[Инд-2-Инкр] = Зн
                                ИначеЕсли Инд = КвоЭлементов-1
                                    Зн = Вычислить(Спис.ПоИндексу(Инд), Окруж)
                                Иначе    
                                    Элементы4[Инд-2-Инкр]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                                КонецЕсли
                                Возврат Неопределено Если НадоВыполнитьВозврат
                            КонецЦикла
                        КонецЕсли
                        Рез = Неопределено
                        Если НЕ Рефлектор.УстановитьЗначение(Спец,ТекОбъект,Элементы4,Зн,ИмпортыИмен)
                            ВызватьИсключение "Ошибка при вызове ("+ИД+"): "+Рефлектор.ОписаниеОшибки
                        КонецЕсли
                    Иначе
                        //отработаем как Перем
                        Зн = Вычислить(Спис.ПоИндексу(2), Окруж)
                        Возврат Неопределено Если НадоВыполнитьВозврат
                        Окруж.ВставитьДействие(ТекИдентификатор, Зн)
                    КонецЕсли
                КонецЕсли
                Возврат Неопределено
            
            ИначеЕсли Код=32 // ИД = "сброс"                 
                //сбрасывает глобальное окружение к стандартному
                ГлобальноеОкружение = Новый клОкружение(СтандартноеОкружение)
                Возврат Неопределено

            ИначеЕсли Код=33 // ИД = "код"                 
                //возвращает текущий список без вычисления его элементов
                Возврат Спис.БезПервогоЭлемента

            ИначеЕсли Код=34 // ИД = "вычислить"                 
                //вычисляет переданное выражение в текущем окружении
                //вариант 1: если передана строка, то она компилируется и вычисляется как код
                //           например, (Вычислить "(+ 3 4)")
                //вариант 2: если передан идентификатор, то его значение извлекается и затем вычисляется
                //           Если значение это строка, то она вычисляется как код,
                //           иначе вычисляется как выражение.
                //           например, (Вычислить МояПеременная)
                //вариант 3: если выражение НЕ является строкой или идентификатором, то оно просто вычисляется
                //           например, (Вычислить (+ 3 4))
                ПроверитьЧислоОперандов(КвоЭлементов=2,ИД)
                Если Спис.ПоИндексу(1) ЭтоТип клИдентификатор Для ТекИдентификатор
                    Рез=Вычислить(ТекИдентификатор, Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                Иначе
                    Рез=Спис.ПоИндексу(1)
                КонецЕсли
                Если Рез ЭтоТип Строка Для СтрПарам
                    Попытка
                        Если Найти(СтрПарам,"#ВключитьФайл",,Истина)>0
                            СтрПарам = ВключитьФайлы(СтрПарам)
                        КонецЕсли
                        ВремГлобОкруж=ГлобальноеОкружение
                        ГлобальноеОкружение=Окруж
                        ВремСтек=СтекВыполненияСписков
                        СтекВыполненияСписков=Новый Стек<клСписок>
                        Рез=Выполнить(Компилировать(СтрПарам))
                        ГлобальноеОкружение=ВремГлобОкруж
                        СтекВыполненияСписков=ВремСтек
                    Исключение Ош
                        ВыводПС("кво "+СтекВыполненияСписков.Количество)
                        СтрПарам=ИзвлечьПозициюОшибки()
                        ГлобальноеОкружение=ВремГлобОкруж
                        СтекВыполненияСписков=ВремСтек
                        ВызватьИсключение Ош.ОписаниеОшибки+" в коде выражения "+СтрПарам+" в операторе Вычислить " 
                    КонецПопытки
                    Возврат Рез
                Иначе
                    СписП=Новый клСписок
                    СписП.ПозицияВТексте=Спис.ПозицияВТексте
                    СписП.ВКонец(Рез)
                    Рез = Вычислить(СписП, Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Возврат Рез
                КонецЕсли
            
            ИначеЕсли Код=35 // ИД = "выбор"                  
                //Вычисляем выбор из нескольких условий.
                //Возвращаем результат того списка, в котором выполнилось условие, 
                //или результат секции Иначе, или Неопределено, когда секция Иначе не задана.
                // (Выбор ((Условие1) Значение1)
                //        ((УсловиеН) ЗначениеН)
                //        (Иначе Значение)
                // )
                ПроверитьЧислоОперандов(КвоЭлементов>=2,ИД)
                Для Инд=1 По КвоЭлементов-1
                    Если Спис.ПоИндексу(Инд) ЭтоТип клСписок Для СписП
                        ПроверитьЧислоОперандов(СписП.Количество()=2,"Выбор (Условие "+Инд+", ожидается 2 операнда)")
                        Если СписП.ПоИндексу(0) ЭтоТип клИдентификатор Для ИДУС
                        И ИДУС.ИД()="иначе"
                            //секция Иначе
                            Рез = Вычислить(СписП.ПоИндексу(1), Окруж)
                            Возврат Неопределено Если НадоВыполнитьВозврат
                            Возврат Рез
                        Иначе
                            //одно из условий
                            Рез = Вычислить(СписП.ПоИндексу(0), Окруж)
                            Возврат Неопределено Если НадоВыполнитьВозврат
                            Если Булево(Рез)
                                Рез = Вычислить(СписП.ПоИндексу(1), Окруж)
                                Возврат Неопределено Если НадоВыполнитьВозврат
                                Возврат Рез
                            КонецЕсли
                        КонецЕсли
                    Иначе
                        ВызватьИсключение "Операнд "+(Инд+1)+" в операторе Выбор не является списком." 
                    КонецЕсли
                КонецЦикла
                Возврат Неопределено
            
            ИначеЕсли Код=36 // ИД = "возврат"                  
                //Выполняет возврат из функции
                //(Возврат Значение)
                ЗначениеВозврата = Неопределено
                Если КвоЭлементов>=2
                    ЗначениеВозврата = Вычислить(Спис.ПоИндексу(1), Окруж)
                КонецЕсли
                НадоВыполнитьВозврат = Истина                   
                Возврат Неопределено
            
            ИначеЕсли Код=37 // ИД = "вызватьисключение"                  
                //Вызывает исключение 
                //(ВызватьИсключение ОписаниеИсключения)
                ПроверитьЧислоОперандов(КвоЭлементов=1 или КвоЭлементов=2,ИД)
                Если КвоЭлементов=1
                    ВызватьИсключение "Вызвано исключение."
                Иначе    
                    Рез = Вычислить(Спис.ПоИндексу(1), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    ВызватьИсключение Строка(Рез)
                КонецЕсли
            
            ИначеЕсли Код=38 // ИД = "поумолчанию"                  
                //Специальная версия Перем
                //Если значение получаемое по Идентификатору равно Неопределено, то выполняем Выражение
                //и присваиваем результат Идентификатору, иначе ничего не делаем.
                //(ПоУмолчанию Идентификатор Выражение)
                ПроверитьЧислоОперандов(КвоЭлементов=3,ИД)
                ТекИдентификатор = ПолучитьИдентификатор(Спис.ПоИндексу(1), Окруж, ИД, 2)
                Рез = Вычислить(ТекИдентификатор, Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Если Рез Это Неопределено
                    Зн = Вычислить(Спис.ПоИндексу(2), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Окруж.ВставитьДействие(ТекИдентификатор, Зн)
                КонецЕсли;
                Возврат Неопределено
            КонецЕсли

        ИначеЕсли Код=-1 //Найти(ИД,".")>0
            //вызов метода объекта (. Тип Член Параметр1 ... ПараметрН)  
            //например, (. ОС Версия) или (. Консоль ВыводПС "Моя строка")
            //если тип вычислять не надо, то можно использовать упрощенную 
            //форму вызова: (ОС.Версия) или (Консоль.ВыводПС "Моя строка")
            ИД=ТекИдентификатор.ОригиналИД
            Спец=Рефлектор.ПолучитьСпецификациюВызова(ИД)
            Если Спец Это Неопределено
                ВызватьИсключение "Ошибка в спецификации вызова ("+ИД+"): "+Рефлектор.ОписаниеОшибки
            КонецЕсли
            ТекОбъект = Неопределено
            Инкр=0
            Если ИД="." 
                //второй параметр это вычисляемый идентификатор типа или объект, 
                //а третий параметр это вычисляемый идентификатор члена
                Рез = Спис.ПоИндексу(1)
                Если Рез ЭтоТип клИдентификатор Для ТекИдентификатор и ТекИдентификатор.Код <> -1
                    Спец.ИмяТипа = Рез.ОригиналИД
                Иначе
                    Рез = Вычислить(Рез,Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                    Если Рез ЭтоТип клИдентификатор
                        Спец.ИмяТипа = Рез.ОригиналИД
                    Иначе
                        ТекОбъект = Рез
                    КонецЕсли
                КонецЕсли
                Спец.ИмяЧлена = ПолучитьИдентификатор(Спис.ПоИндексу(2), Окруж, ИД, 3)
                Инкр=2
            КонецЕсли
            Если ТекОбъект Это Неопределено
                //получим объект
                Если Лев(Спец.ИмяТипа,1)="@"
                    Спец.ИмяТипа=Сред(Спец.ИмяТипа,2)
                    ТекОбъект = Неопределено
                Иначе
                    ТекОкруж = Окруж.НайтиОкружение(Спец.ИмяТипа)
                    Если ТекОкруж Это Неопределено
                        //возможно это статический вызов
                        ТекОбъект = Неопределено
                    Иначе
                        ТекОбъект = ТекОкруж.ПолучитьДействие(Спец.ИмяТипа)
                    КонецЕсли
                КонецЕсли
            КонецЕсли
            //вычислим аргументы метода
            Массив Элементы2[КвоЭлементов-2-Инкр] тип Объект
            Массив Элементы2ид[КвоЭлементов-2-Инкр] тип клИдентификатор
            Если КвоЭлементов=1+Инкр
                Элементы2=Неопределено
            Иначе
                Для Инд=1+Инкр По КвоЭлементов-1
                    Если Спис.ПоИндексу(Инд) ЭтоТип клИдентификатор Для ИДСсыл
                        Элементы2ид[Инд-1-Инкр]=ИДСсыл
                    КонецЕсли
                    Элементы2[Инд-1-Инкр]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                    Возврат Неопределено Если НадоВыполнитьВозврат
                КонецЦикла
            КонецЕсли
            Рез = Неопределено
            Если НЕ Рефлектор.ПолучитьЗначение(Спец,ТекОбъект,Элементы2,Рез,ИмпортыИмен)
                ВызватьИсключение "Ошибка при вызове ("+ИД+"): "+Рефлектор.ОписаниеОшибки
            КонецЕсли
            //надо вернуть в переменную значение, если она возможно??? передавалась по ссылке
            Если Элементы2 ЭтоНе Неопределено
                Для Инд=0 По Элементы2.Количество-1
                    ИДСсыл=Элементы2ид[Инд]
                    Если ИДСсыл ЭтоНе Неопределено
                        Окруж.ВставитьДействие(ИДСсыл, Элементы2[Инд])
                    КонецЕсли
                КонецЦикла
            КонецЕсли
            Возврат Рез
            
        ИначеЕсли Код=-2 //Найти(ИД,":")>0
            //конвеер функций (Функ1:Функ2:ФункН Параметр1 ... ПараметрН)  
            //вычисляется справа налево
            //самая первая вчисляемая функция (правая) может иметь несколько параметров
            //остальные функции должны принимать результат предыдущей
            //например, (СокрЛП:ВРег:Лев "  вася  пупкин  " 8)
            масИД=СтрРазделить(ИД,":",Ложь)
            Элементы = Новый Объект[КвоЭлементов-2]
            Для Инд=1 По КвоЭлементов-1
                Элементы[Инд-1]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
            КонецЦикла
            Рез=Неопределено
            КвоП=масИД.Количество-1
            Для Инд=КвоП По 0 Шаг -1 
                ИД=масИД[Инд]
                Действие = Вычислить(Новый клИдентификатор(ИД), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
                Если Инд<КвоП
                    Элементы = Новый Объект[0]{Рез}
                КонецЕсли
                Рез=ВыполнитьДействие(Действие, ИД, Элементы, Окруж)
            КонецЦикла
            Возврат Рез            
            
        Иначе                                  
            //(Действие Параметры...)
            //остался только один вариант
            //надо выполнить действие из окружения
            Действие = Вычислить(ТекИдентификатор, Окруж)
            Возврат Неопределено Если НадоВыполнитьВозврат
            Элементы = Новый Объект[КвоЭлементов-2]
            Для Инд=1 По КвоЭлементов-1
                Элементы[Инд-1]=Вычислить(Спис.ПоИндексу(Инд), Окруж)
                Возврат Неопределено Если НадоВыполнитьВозврат
            КонецЦикла
            Возврат ВыполнитьДействие(Действие, ИД, Элементы, Окруж)
        КонецЕсли
        Возврат Неопределено
    КонецФункции    
    
    //---------------------------
    Функция ПолучитьИдентификатор(ИД тип Объект, Окруж тип клОкружение, ИмяОператора тип Строка, НомерПараметра тип Целое) тип клИдентификатор
        Если ИД ЭтоНеТип клИдентификатор
            ИД = Вычислить(ИД, Окруж)
        КонецЕсли
        Если ИД ЭтоНеТип клИдентификатор
            ВызватьИсключение "Параметр "+НомерПараметра+" в операторе "+ТРег(ИмяОператора)+" не является идентификатором." 
        КонецЕсли
        Возврат ИД
    КонецФункции    
    
    //---------------------------
    Функция ВыполнитьДействие(Действие тип Объект, ИД тип Строка, Аргументы тип Объект[], Окруж тип клОкружение) тип Объект
        
        КоличествоОперандов=Аргументы.Количество
        
        Если Действие ЭтоТип клВстроеннаяФункция Для ВСФЯ
            Если ВСФЯ.ДелегатФункции ЭтоТип ФункцияСМассивомОперандов Для ФСМО
                Возврат ФСМО.Выполнить(ВСФЯ.Имя,Аргументы)
    
            ИначеЕсли ВСФЯ.ДелегатФункции ЭтоТип ФункцияБезОперандов Для ФБО
                ОшибкаЕслиОперандовБольше(0,КоличествоОперандов,ИД)
                Возврат ФБО.Выполнить(ВСФЯ.Имя)
                
            ИначеЕсли ВСФЯ.ДелегатФункции ЭтоТип ФункцияСОднимОперандом Для ФСОО
                ОшибкаЕслиОперандовБольше(1,КоличествоОперандов,ИД)
                Возврат ФСОО.Выполнить(ВСФЯ.Имя,?(КоличествоОперандов>=1,Аргументы[0],Неопределено))
                
            ИначеЕсли ВСФЯ.ДелегатФункции ЭтоТип ФункцияСДвумяОперандами Для ФСДО
                ОшибкаЕслиОперандовБольше(2,КоличествоОперандов,ИД)
                Возврат ФСДО.Выполнить(ВСФЯ.Имя,?(КоличествоОперандов>=1,Аргументы[0],Неопределено),
                                       ?(КоличествоОперандов>=2,Аргументы[1],Неопределено))
                
            ИначеЕсли ВСФЯ.ДелегатФункции ЭтоТип ФункцияСТремяОперандами Для ФСТО
                ОшибкаЕслиОперандовБольше(3,КоличествоОперандов,ИД)
                Возврат ФСТО.Выполнить(ВСФЯ.Имя,?(КоличествоОперандов>=1,Аргументы[0],Неопределено),
                                       ?(КоличествоОперандов>=2,Аргументы[1],Неопределено),
                                       ?(КоличествоОперандов>=3,Аргументы[2],Неопределено))
            КонецЕсли    
        
        
        ИначеЕсли Действие ЭтоТип клФункцияПользователя Для ФПЛЗ
            
            ОкружФункции = Новый клОкружение(ФПЛЗ.ИдентификаторыПараметров,Аргументы,ФПЛЗ.Окружение)
            Рез = Вычислить(ФПЛЗ.ТелоФункции,ОкружФункции)
            Если НадоВыполнитьВозврат
                Рез = ЗначениеВозврата
            КонецЕсли
            НадоВыполнитьВозврат = Ложь
            ЗначениеВозврата = Неопределено
            Возврат Рез
        
        ИначеЕсли Действие ЭтоТип System.Delegate Для ФСД
            Возврат ФСД.ВыполнитьДинамически(Аргументы)
        
        ИначеЕсли Аргументы.Количество>0
            ВызватьИсключение "Значение вызывается как действие."
            
        Иначе
            //просто значение
            Возврат Действие
        КонецЕсли
    КонецФункции    
    

#КонецОбласти      
        
      
#Область ВстроенныеФункцииЯзыка

    //---------------------------
    Функция ОператорСМассивомОперандов(ИмяФункции тип Строка, Парам Операнды тип Объект[]) тип Объект 
        Если Операнды Это Неопределено
            Возврат 0
        КонецЕсли
        КвоОперандов=Операнды.Количество
        Перем Рез тип Объект = Неопределено
        
        Выбор Для ИмяФункции
        Когда "стршаблон" Тогда    
            ОшибкаЕслиОперандовМеньше(2,КвоОперандов,ИмяФункции)
            ОшибкаЕслиОперандовБольше(11,КвоОперандов,ИмяФункции)
            Выбор Для КвоОперандов
            Когда 2 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1])    
            Когда 3 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2])    
            Когда 4 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3])    
            Когда 5 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4])    
            Когда 6 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4],Операнды[5])    
            Когда 7 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4],Операнды[5],Операнды[6])    
            Когда 8 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4],Операнды[5],Операнды[6],Операнды[7])    
            Когда 9 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4],Операнды[5],Операнды[6],Операнды[7],Операнды[8])    
            Когда 10 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4],Операнды[5],Операнды[6],Операнды[7],Операнды[8],Операнды[9])    
            Когда 11 Тогда Возврат СтрШаблон(Строка(Операнды[0]),Операнды[1],Операнды[2],Операнды[3],Операнды[4],Операнды[5],Операнды[6],Операнды[7],Операнды[8],Операнды[9],Операнды[10])    
            КонецВыбора
        Когда "стрнайти" Тогда    
            ОшибкаЕслиОперандовМеньше(2,КвоОперандов,ИмяФункции)
            ОшибкаЕслиОперандовБольше(5,КвоОперандов,ИмяФункции)
            Выбор Для КвоОперандов
            Когда 2 Тогда Возврат СтрНайти(Строка(Операнды[0]),Строка(Операнды[1]))    
            Когда 3 Тогда Возврат СтрНайти(Строка(Операнды[0]),Строка(Операнды[1]),Операнды[2])    
            Когда 4 Тогда Возврат СтрНайти(Строка(Операнды[0]),Строка(Операнды[1]),Операнды[2],Операнды[3])    
            Когда 5 Тогда Возврат СтрНайти(Строка(Операнды[0]),Строка(Операнды[1]),Операнды[2],Операнды[3],Операнды[4])    
            КонецВыбора
        Когда "дэл","добавитьэлемент" Тогда          
            ОшибкаЕслиОперандовМеньше(1,КвоОперандов,ИмяФункции)
            Операнд1 = Операнды[0]
            Если КвоОперандов = 1
                Спис = Новый клСписок
                Спис.ВКонец(Операнд1)
                Возврат Спис
            Иначе    
                Если Операнд1 ЭтоТип клСписок Для Спис
                    Для Инд=1 По КвоОперандов-1
                        Спис.ВКонец(Операнды[Инд])
                    КонецЦикла
                    Возврат Спис
                Иначе
                    //может это коллекция имеющая свойство Добавить, Add, AddAppend?
                    Рез = Неопределено
                    Успех = 1
                    Для Каждого Имя тип Строка Из {"Добавить","Вставить","Add","Append","Push","Enqueue"} Цикл
                        Для Инд=1 По КвоОперандов-1
                            Если Рефлектор.ПолучитьЗначение("",Имя,Операнд1,{Операнды[Инд]},Рез)
                                Успех++
                            КонецЕсли
                        КонецЦикла
                        ПрерватьЕсли Успех = КвоОперандов 
                    КонецЦикла
                    Если Успех <> КвоОперандов
                        ВызватьИсключение "Ошибка в функции ДЭЛ: У объекта "+Операнд1+" не удалось найти метода добавления элемента." 
                    КонецЕсли
                    Возврат Операнд1
                КонецЕсли           
            КонецЕсли
        Когда "сэл","сложитьэлементы" Тогда          
            ОшибкаЕслиОперандовМеньше(1,КвоОперандов,ИмяФункции)
            Спис = Новый клСписок
            Для Инд=0 По КвоОперандов-1
                Если Операнды[Инд] ЭтоТип клСписок Для ЗнСпис
                    Для Инд2=0 По ЗнСпис.Количество-1
                        Спис.ВКонец(ЗнСпис.ПоИндексу(Инд2))
                    КонецЦикла
                Иначе
                    Спис.ВКонец(Операнды[Инд])
                КонецЕсли
            КонецЦикла
            Возврат Спис;
        Когда "знчтипа" Тогда          
            РезБул=Ложь
            Для Инд=1 По КвоОперандов-1
                Если Операнды[Инд] ЭтоТип Тип
                    тп = Операнды[Инд]
                ИначеЕсли Операнды[Инд] ЭтоТип Строка Для Стр
                    тп = Рефлектор.НайтиТип(Стр,ИмпортыИмен)
                КонецЕсли
                РезБул = РезБул или ТипЗнч(Операнды[0]) Это тп
                Прервать Если РезБул
            КонецЦикла
            Возврат РезБул
        Когда "+" При КвоОперандов=1, 
              "-" При КвоОперандов=1 Тогда    
            //унарные + и -
            Рез = 0
            Выбор Для ИмяФункции
            Когда "+" Тогда    
                Рез += Операнды[0]
            Когда "-" Тогда    
                Рез -= Операнды[0]
            КонецВыбора
        Когда "срезстроки"
            ОшибкаЕслиОперандовМеньше(1,КвоОперандов,ИмяФункции)
            ОшибкаЕслиОперандовБольше(4,КвоОперандов,ИмяФункции)
            Опер0=Строка(Операнды[0])
            Опер3=?(КвоОперандов>3 и Операнды[3] Определено,Целое(Операнды[3]),1)//шаг
            Если Опер3>=0
                Опер1=?(КвоОперандов>1 и Операнды[1] Определено,Целое(Операнды[1]),0)
                Опер2=?(КвоОперандов>2 и Операнды[2] Определено,Целое(Операнды[2]),СтрДлина(Опер0)-1)
            Иначе
                Опер1=?(КвоОперандов>1 и Операнды[1] Определено,Целое(Операнды[1]),СтрДлина(Опер0)-1)
                Опер2=?(КвоОперандов>2 и Операнды[2] Определено,Целое(Операнды[2]),0)
            КонецЕсли
            Возврат СрезСтроки(Опер0,Опер1,Опер2,Опер3)
        Когда "срезмассива"
            ОшибкаЕслиОперандовМеньше(1,КвоОперандов,ИмяФункции)
            ОшибкаЕслиОперандовБольше(4,КвоОперандов,ИмяФункции)
            Опер0м=ЗнчКТипу(Операнды[0],"System.Array")
            Опер3=?(КвоОперандов>3 и Операнды[3] Определено,Целое(Операнды[3]),1)//шаг
            Если Опер3>=0
                Опер1=?(КвоОперандов>1 и Операнды[1] Определено,Целое(Операнды[1]),0)
                Опер2=?(КвоОперандов>2 и Операнды[2] Определено,Целое(Операнды[2]),Опер0м.Количество-1)
            Иначе
                Опер1=?(КвоОперандов>1 и Операнды[1] Определено,Целое(Операнды[1]),Опер0м.Количество-1)
                Опер2=?(КвоОперандов>2 и Операнды[2] Определено,Целое(Операнды[2]),0)
            КонецЕсли
            Возврат СрезМассива(Опер0м,Опер1,Опер2,Опер3)
        Когда "командасистемы"      
            ОшибкаЕслиОперандовМеньше(1,КвоОперандов,ИмяФункции)
            ОшибкаЕслиОперандовБольше(4,КвоОперандов,ИмяФункции)
            Опер1с=?(КвоОперандов>1 и Операнды[1] Определено,Строка(Операнды[1]),"")
            Опер2б=?(КвоОперандов>2 и Операнды[2] Определено,Булево(Операнды[2]),Ложь)
            Опер3=?(КвоОперандов>3 и Операнды[3] Определено,Целое(Операнды[3]),0)
            Возврат КомандаСистемы(Строка(Операнды[0]),Опер1с,Опер2б,Опер3)
        Когда "запуститьприложение"      
            ОшибкаЕслиОперандовМеньше(1,КвоОперандов,ИмяФункции)
            ОшибкаЕслиОперандовБольше(4,КвоОперандов,ИмяФункции)
            Опер1с=?(КвоОперандов>1 и Операнды[1] Определено,Строка(Операнды[1]),"")
            Опер2б=?(КвоОперандов>2 и Операнды[2] Определено,Булево(Операнды[2]),Ложь)
            Опер3=?(КвоОперандов>3 и Операнды[3] Определено,Целое(Операнды[3]),0)
            Возврат ЗапуститьПриложение(Строка(Операнды[0]),Опер1с,Опер2б,Опер3)
        Иначе
            ОшибкаЕслиОперандовМеньше(2,КвоОперандов,ИмяФункции)
            Рез = Операнды[0]
            Выбор Для ИмяФункции
            Когда "или" Тогда    
                БулРез = Булево(Рез)
                Рез = БулРез
                Если БулРез
                    Возврат Рез    
                КонецЕсли
            Когда "и" Тогда    
                БулРез = Булево(Рез)
                Рез = БулРез
                Если НЕ БулРез
                    Возврат Рез    
                КонецЕсли
            КонецВыбора
            Для Инд=1 По КвоОперандов-1
                Выбор Для ИмяФункции
                Когда "+" Тогда    
                    Рез += Операнды[Инд]
                Когда "-" Тогда    
                    Рез -= Операнды[Инд]
                Когда "*" Тогда    
                    Рез *= Операнды[Инд]
                Когда "/" Тогда    
                    Рез /= Операнды[Инд]
                Когда "или" Тогда    
                    БулРез = Булево(Рез) Или Булево(Операнды[Инд])
                    Рез = БулРез
                    Если БулРез
                        Прервать    
                    КонецЕсли
                Когда "и" Тогда    
                    БулРез = Булево(Рез) И Булево(Операнды[Инд])
                    Рез = БулРез
                    Если НЕ БулРез
                        Прервать    
                    КонецЕсли
                Когда "бити" Тогда        
                    Рез = Бит64(Рез) БитИ Бит64(Операнды[Инд])
                Когда "битили" Тогда     
                    Рез = Бит64(Рез) БитИли Бит64(Операнды[Инд])
                Когда "^","**" Тогда    
                    Рез ^= Операнды[Инд]
                Когда "макс" Тогда    
                    Если Операнды[Инд] > Рез 
                        Рез = Операнды[Инд]
                    КонецЕсли
                Когда "мин" Тогда    
                    Если Операнды[Инд] < Рез 
                        Рез = Операнды[Инд]
                    КонецЕсли
                Когда "&" Тогда    
                    Рез &= Операнды[Инд]
                Иначе
                    ВызватьИсключение "Функция "+ИмяФункции+" не определена."
                КонецВыбора
            КонецЦикла
        КонецВыбора
        Возврат Рез
    КонецФункции 

    //---------------------------
    Функция ОператорСТремяОперандами(ИмяФункции тип Строка, Операнд1 тип Объект, Операнд2 тип Объект, Операнд3 тип Объект) тип Объект 
        Выбор Для ИмяФункции
        Когда "сред" Тогда
            Если Операнд2 Это Неопределено
                Операнд2=1
            КонецЕсли    
            Если Операнд1 ЭтоТип клСписок Для Спис
                //возвращаем элементы списка начиная с указанного
                //(Сред (Список 1 2 3 4 5) НачНомер Кво)
                Если Операнд3 Это Неопределено
                    Возврат Спис.ФункСред(Целое(Операнд2),-1)
                Иначе
                    Возврат Спис.ФункСред(Целое(Операнд2),Целое(Операнд3))
                КонецЕсли
            Иначе
                Если Операнд3 Это Неопределено
                    Возврат Сред(Строка(Операнд1),Целое(Операнд2))
                Иначе
                    Возврат Сред(Строка(Операнд1),Целое(Операнд2),Целое(Операнд3))
                КонецЕсли
            КонецЕсли
        Когда "стрзаменить" Тогда    
            Возврат СтрЗаменить(Строка(Операнд1),Строка(Операнд2),Строка(Операнд3))
        Когда "стрразделить" Тогда    
            Возврат СтрРазделить(Строка(Операнд1),Строка(Операнд2),Булево(Операнд3))
        Когда "уэл","установитьэлемент"
            Инд = ?(Операнд3 Это Неопределено, 0, Целое(Операнд3))
            ОшибкаИнд=Ложь
            Если Операнд1 ЭтоТип клСписок Для Спис
                Если Инд < 0 или Инд >= Спис.Количество
                    ОшибкаИнд=Истина
                Иначе
                    Спис.ПоИндексу(Инд,Операнд2)
                    Возврат Неопределено
                КонецЕсли
            ИначеЕсли Операнд1 ЭтоТип System.Array Для Мас
                Если Инд < 0 или Инд >= Мас.Length
                    ОшибкаИнд=Истина
                Иначе
                    Мас.SetValue(Операнд2,Инд)
                    Возврат Неопределено
                КонецЕсли
            Иначе
                //может это коллекция имеющая свойство Item?
                Рез = Неопределено
                Если НЕ Рефлектор.УстановитьЗначение(Операнд1.ПолучитьТип,"Item",Операнд1,{Объект(Инд)},Операнд2)
                    ВызватьИсключение "Ошибка в функции УЭЛ: "+Рефлектор.ОписаниеОшибки+"." 
                КонецЕсли
                Возврат Рез
            КонецЕсли            
            Если ОшибкаИнд
                ВызватьИсключение "В функци УЭЛ индекс за пределами массива или коллекции."
            КонецЕсли
        
        Иначе
            ВызватьИсключение "Функция "+ИмяФункции+" не определена."
        КонецВыбора
    КонецФункции 

    //---------------------------
    Функция ОператорСДвумяОперандами(ИмяФункции тип Строка, Операнд1 тип Объект, Операнд2 тип Объект) тип Объект 
        Выбор Для ИмяФункции
        Когда "%"           Возврат Операнд1 % Операнд2
        Когда ">"           Возврат Операнд1 > Операнд2
        Когда "<"           Возврат Операнд1 < Операнд2
        Когда ">="          Возврат Операнд1 >= Операнд2
        Когда "<="          Возврат Операнд1 <= Операнд2
        Когда "="           Возврат Операнд1 = Операнд2
        Когда "<>", "!="    Возврат Операнд1 <> Операнд2
        Когда "это"         Возврат Операнд1 Это Операнд2
        Когда "этоне"       Возврат Операнд1 ЭтоНе Операнд2
        Когда "этотип"      
            Если Операнд2 ЭтоТип Тип
                Возврат Операнд1 ЭтоТип ТипКТипу(Операнд2,"Тип")
            Иначе
                Возврат ТипЗнч(Операнд1)=Рефлектор.НайтиТип(Строка(Операнд2),ИмпортыИмен)
            КонецЕсли
        Когда "этонетип"
            Если Операнд2 ЭтоТип Тип
                Возврат Операнд1 ЭтоНеТип ТипКТипу(Операнд2,"Тип")
            Иначе
                Возврат НЕ ТипЗнч(Операнд1)=Рефлектор.НайтиТип(Строка(Операнд2),ИмпортыИмен)
            КонецЕсли
        Когда "исклили"     Возврат Булево(Операнд1) ИсклИли Булево(Операнд2)
        Когда "битисклили"  Возврат Бит64(Операнд1) БитИсклИли Бит64(Операнд2)
        
        Когда "лев"         
            Если Операнд2 Это Неопределено
                Операнд2=1
            КонецЕсли    
            Если Операнд1 ЭтоТип клСписок Для Спис
                //возвращаем первый элемент списка
                //(Лев (Список 1 2 3 4 5))
                Возврат Спис.ФункЛев(Целое(Операнд2))      
            Иначе
                Возврат Лев(Строка(Операнд1),Целое(Операнд2))
            КонецЕсли
        
        Когда "прав"        
            Если Операнд2 Это Неопределено
                Операнд2=1
            КонецЕсли    
            Если Операнд1 ЭтоТип клСписок Для Спис
                //возвращаем первый элемент списка
                //(Прав (Список 1 2 3 4 5))
                Возврат Спис.ФункПрав(Целое(Операнд2))      
            Иначе
                Возврат Прав(Строка(Операнд1),Целое(Операнд2))
            КонецЕсли
        
        Когда "еслинеопределено", "??" Тогда    
            Если Операнд1 ЭтоНе Неопределено
                Возврат Операнд1
            Иначе
                Возврат Операнд2
            КонецЕсли    
        Когда "найти"            Возврат Найти(Строка(Операнд1),Строка(Операнд2))
        Когда "формат"           Возврат Формат(Операнд1,Строка(Операнд2))
        Когда "добавитьмесяц"    Возврат ДобавитьМесяц(Дата(Операнд1),Целое(Операнд2))
        Когда "окр"              Возврат Окр(Число(Операнд1),Целое(Операнд2))
        Когда "найтисконца"      Возврат НайтиСКонца(Строка(Операнд1),Строка(Операнд2))
        
        Когда "нстр"             Возврат НСтр(Строка(Операнд1),Строка(Операнд2))
        Когда "систр"            
            Если Операнд2 Это Неопределено
                Возврат СиСтр(Строка(Операнд1))
            Иначе
                Возврат СиСтр(Строка(Операнд1),Булево(Операнд2))
            КонецЕсли
        
        Когда "знчктипу"
            Перем РезОбъект тип Объект = Неопределено
            Если Операнд2 ЭтоТип Тип
                Если НЕ Рефлектор.ЗначениеКТипу(Операнд1,ТипКТипу(Операнд2,"Тип"),РезОбъект,Ложь,ИмпортыИмен)
                    ВызватьИсключение Рефлектор.ОписаниеОшибки 
                КонецЕсли
            Иначе
                Если НЕ Рефлектор.ЗначениеКТипу(Операнд1,Строка(Операнд2),РезОбъект,Ложь,ИмпортыИмен)
                    ВызватьИсключение Рефлектор.ОписаниеОшибки 
                КонецЕсли
            КонецЕсли
            Возврат РезОбъект
        
        Когда "стрначинаетсяс"  Возврат СтрНачинаетсяС(Строка(Операнд1),Строка(Операнд2))
        Когда "стрзаканчиваетсяна"  Возврат СтрЗаканчиваетсяНа(Строка(Операнд1),Строка(Операнд2))
        Когда "стрчисловхождений"   Возврат СтрЧислоВхождений(Строка(Операнд1),Строка(Операнд2))
        Когда "стрполучитьстроку"   Возврат СтрПолучитьСтроку(Строка(Операнд1),Целое(Операнд2))
        Когда "стрсравнить"         Возврат СтрСравнить(Строка(Операнд1),Строка(Операнд2))
        Когда "стрсоединить"        
            Если Операнд1 ЭтоТип клСписок
                Операнд1 = Операнд1.Данные    
            КонецЕсли
            Если Операнд2 Это Неопределено
                Возврат СтрСоединить(Операнд1)
            Иначе
                Возврат СтрСоединить(Операнд1,Строка(Операнд2))
            КонецЕсли
        
        Когда "кодсимвола"          Возврат КодСимвола(Строка(Операнд1),?(Операнд2 Это Неопределено,1,Целое(Операнд2)))
        Когда "logn"                Возврат LogN(ДВещ(Операнд1),ДВещ(Операнд2))
        Когда "atan2"               Возврат ATan2(ДВещ(Операнд1),ДВещ(Операнд2))
        Когда "pow"                 Возврат Pow(ДВещ(Операнд1),ДВещ(Операнд2))
        
        Когда "пэл","получитьэлемент"
            Инд = ?(Операнд2 Это Неопределено, 0, Целое(Операнд2))
            Если Операнд1 ЭтоТип клСписок Для Спис
                Если Спис.Количество=0
                    Возврат Неопределено
                Иначе
                    Возврат Спис.ПоИндексу(Инд)
                КонецЕсли
            ИначеЕсли Операнд1 ЭтоТип System.Array Для Мас
                Если Мас.Length=0
                    Возврат Неопределено
                Иначе
                    Возврат Мас[Инд]
                КонецЕсли
            ИначеЕсли Операнд1 ЭтоТип Строка Для Стр
                Если Стр.Length=0
                    Возврат Неопределено
                Иначе
                    Возврат Стр[Инд]
                КонецЕсли
            Иначе
                //может это коллекция имеющая свойство Item?
                Рез = Неопределено
                Если НЕ Рефлектор.ПолучитьЗначение(Операнд1.ПолучитьТип,"Item",Операнд1,{Объект(Инд)},Рез)
                    ВызватьИсключение "Не поддерживается тип второго операнда в функции ПЭЛ: "+Операнд1.ПолучитьТип.ВСтроку+"." 
                КонецЕсли
                Возврат Рез
            КонецЕсли            
        
        Иначе
            ВызватьИсключение "Функция "+ИмяФункции+" не определена."
        КонецВыбора
    КонецФункции 

    //---------------------------
    Функция ОператорСОднимОперандом(ИмяФункции тип Строка, Операнд тип Объект) тип Объект 
        Выбор Для ИмяФункции
        Когда "не"      Возврат не Булево(Операнд)
        Когда "значениезаполнено"  Возврат ЗначениеЗаполнено(Операнд)
        Когда "длина"  
            Если Операнд ЭтоТип Строка Для Стр
                Возврат СтрДлина(Стр)
            ИначеЕсли Операнд ЭтоТип клСписок Для Спис
                Возврат Спис.Количество
            ИначеЕсли Операнд ЭтоТип System.Collections.ICollection Для Collect
                Возврат Collect.Count
            ИначеЕсли Операнд ЭтоТип System.Array Для Arr
                Возврат Arr.Length
            Иначе
                ВызватьИсключение "Не поддерживается тип операнда в функции Длина: "+Операнд.ПолучитьТип.ВСтроку+"." 
            КонецЕсли    
        Когда "врег"    Возврат ВРег(Строка(Операнд))
        Когда "нрег"    Возврат НРег(Строка(Операнд))
        Когда "трег"    Возврат ТРег(Строка(Операнд))
        Когда "сокрл"   Возврат СокрЛ(Строка(Операнд))
        Когда "сокрп"   Возврат СокрП(Строка(Операнд))
        Когда "сокрлп"  Возврат СокрЛП(Строка(Операнд))
        Когда "пустаястрока","пустаястрока?"        Возврат пустаястрока(Строка(Операнд))
        Когда "стрколичествострок"  Возврат стрколичествострок(Строка(Операнд))
        Когда "стрчислострок"       Возврат стрчислострок(Строка(Операнд))
        Когда "стрдлина"            Возврат стрдлина(Строка(Операнд))
        
        Когда "начгода","началогода"          Возврат начгода(Дата(Операнд))
        Когда "конгода","конецгода"           Возврат конгода(Дата(Операнд))
        Когда "начквартала","началоквартала"  Возврат начквартала(Дата(Операнд))
        Когда "конквартала","конецквартала"   Возврат конквартала(Дата(Операнд))
        Когда "начмесяца","началомесяца"      Возврат начмесяца(Дата(Операнд))
        Когда "конмесяца","конецмесяца"       Возврат конмесяца(Дата(Операнд))
        Когда "начнедели","началонедели"      Возврат начнедели(Дата(Операнд))
        Когда "коннедели","конецнедели"       Возврат коннедели(Дата(Операнд))
        Когда "начдня","началодня"            Возврат начдня(Дата(Операнд))
        Когда "кондня","конецдня"             Возврат кондня(Дата(Операнд))
        Когда "наччаса","началочаса"          Возврат наччаса(Дата(Операнд))
        Когда "кончаса","конецчаса"           Возврат кончаса(Дата(Операнд))
        Когда "начминуты","началоминуты"      Возврат начминуты(Дата(Операнд))
        Когда "конминуты","конецминуты"       Возврат конминуты(Дата(Операнд))
        Когда "год"             Возврат год(Дата(Операнд))
        Когда "квартал"         Возврат квартал(Дата(Операнд))
        Когда "месяц"           Возврат месяц(Дата(Операнд))
        Когда "день"            Возврат день(Дата(Операнд))
        Когда "час"             Возврат час(Дата(Операнд))
        Когда "минута"          Возврат минута(Дата(Операнд))
        Когда "секунда"         Возврат секунда(Дата(Операнд))
        Когда "деньгода"        Возврат деньгода(Дата(Операнд))
        Когда "деньнедели"      Возврат деньнедели(Дата(Операнд))
        Когда "неделягода"      Возврат неделягода(Дата(Операнд))
        Когда "датагод"         Возврат датагод(Дата(Операнд))
        Когда "датаквартал"     Возврат датаквартал(Дата(Операнд))
        Когда "датамесяц"       Возврат датамесяц(Дата(Операнд))
        Когда "датачисло"       Возврат датачисло(Дата(Операнд))
        Когда "номернеделигода" Возврат номернеделигода(Дата(Операнд))
        Когда "номерднягода"    Возврат номерднягода(Дата(Операнд))
        Когда "номерднянедели"  Возврат номерднянедели(Дата(Операнд))
        
        Когда "помодулю","abs","абс"  Возврат abs(Число(Операнд))
        Когда "знак","sign"     Возврат sign(Число(Операнд))
        Когда "синус","sin"     Возврат Число(sin(ДВещ(Операнд)))
        Когда "косинус","cos"   Возврат Число(cos(ДВещ(Операнд)))
        Когда "корень","sqrt"   Возврат Число(sqrt(ДВещ(Операнд)))
        Когда "log"       Возврат Число(Log(ДВещ(Операнд)))
        Когда "log10"     Возврат Число(log10(ДВещ(Операнд)))
        Когда "тангенс","tan"   Возврат Число(tan(ДВещ(Операнд)))
        Когда "asin"      Возврат Число(asin(ДВещ(Операнд)))
        Когда "acos"      Возврат Число(acos(ДВещ(Операнд)))
        Когда "atan"      Возврат Число(atan(ДВещ(Операнд)))
        Когда "exp"       Возврат Exp(ДВещ(Операнд))
        Когда "цел"       Возврат Цел(Число(Операнд))
        Когда "дроб"      Возврат Дроб(Число(Операнд))
        
        Когда "число"     Возврат Число(Операнд)
        Когда "байт", "бит8"    Возврат Байт(Операнд)
        Когда "целое", "цел32"  Возврат Целое(Операнд)
        Когда "цел8"      Возврат Цел8(Операнд)
        Когда "цел16"     Возврат Цел16(Операнд)
        Когда "цел64"     Возврат Цел64(Операнд)
        Когда "бит16"     Возврат Бит16(Операнд)
        Когда "бит32"     Возврат Бит32(Операнд)
        Когда "бит64"     Возврат Бит64(Операнд)
        Когда "строка"    Возврат Строка(Операнд)
        Когда "символ"
            Если Операнд ЭтоТип Строка Для Стр
                Возврат Символ(Строка(Операнд))
            Иначе    
                Возврат Символ(Целое(Операнд))
            КонецЕсли
        Когда "дата"      
            Перем РезДт тип Дата
            Если НЕ РаспознатьДату(Операнд,РезДт)
                ВызватьИсключение "Не удалось распознать дату."
            КонецЕсли
            Возврат РезДт
        Когда "булево"    Возврат Булево(Операнд)
        Когда "объект"    Возврат Объект(Операнд)
        Когда "вещ"       Возврат Вещ(Операнд)
        Когда "двещ"      Возврат ДВещ(Операнд)
        Когда "целукз"    Возврат ЦелУкз(Цел64(Операнд))
        Когда "битукз"    Возврат БитУкз(Бит64(Операнд))
        
        Когда "неопределено?"    Возврат Операнд Это Неопределено
        Когда "определено?"      Возврат Операнд Определено
        Когда "список?"          Возврат Операнд ЭтоТип клСписок
        Когда "число?"           Возврат Операнд ЭтоТип Число
        Когда "байт?", "бит8?"   Возврат Операнд ЭтоТип Байт
        Когда "целое?", "цел32?" Возврат Операнд ЭтоТип Целое
        Когда "цел8?"      Возврат Операнд ЭтоТип Цел8
        Когда "цел16?"     Возврат Операнд ЭтоТип Цел16
        Когда "цел64?"     Возврат Операнд ЭтоТип Цел64
        Когда "бит16?"     Возврат Операнд ЭтоТип Бит16
        Когда "бит32?"     Возврат Операнд ЭтоТип Бит32
        Когда "бит64?"     Возврат Операнд ЭтоТип Бит64
        Когда "строка?"    Возврат Операнд ЭтоТип Строка
        Когда "символ?"    Возврат Операнд ЭтоТип Символ
        Когда "дата?"      Возврат Операнд ЭтоТип Дата
        Когда "булево?"    Возврат Операнд ЭтоТип Булево
        Когда "объект?"    Возврат Операнд ЭтоТип Объект
        Когда "вещ?"       Возврат Операнд ЭтоТип Вещ
        Когда "двещ?"      Возврат Операнд ЭтоТип ДВещ
        Когда "целукз?"    Возврат Операнд ЭтоТип ЦелУкз
        Когда "битукз?"    Возврат Операнд ЭтоТип БитУкз
        
        Когда "тип"        Возврат Рефлектор.НайтиТип(Строка(Операнд),ИмпортыИмен)
        Когда "типзнч"     Возврат ТипЗнч(Операнд)
        Когда "типзнчстр"  Возврат Рефлектор.ПолучитьПредставлениеТипа(Операнд.ПолучитьТип)
        
        Когда "числоизшестнадцатеричнойстроки"    Возврат ЧислоИзШестнадцатеричнойСтроки(Строка(Операнд))
        Когда "числоиздвоичнойстроки"             Возврат ЧислоИзДвоичнойСтроки(Строка(Операнд))
        Когда "получитьимявременногофайла"        Возврат ПолучитьИмяВременногоФайла(Строка(Операнд))
        Когда "этомассив","массив?"               Возврат Операнд ЭтоТип System.Array 
        Когда "функция?"
            Если Операнд ЭтоТип клВстроеннаяФункция 
             или Операнд ЭтоТип клФункцияПользователя
             или Операнд ЭтоТип System.Delegate
                Возврат Истина
            КонецЕсли
            Возврат Ложь
        Когда "пусто?"
            Возврат Истина Если Операнд Это Неопределено
            Если Операнд ЭтоТип Строка Для Стр
                Возврат СтрДлина(Стр)=0
            ИначеЕсли Операнд ЭтоТип клСписок Для Спис
                Возврат Спис.Количество=0
            ИначеЕсли Операнд ЭтоТип System.Collections.ICollection Для Collect
                Возврат Collect.Count=0
            ИначеЕсли Операнд ЭтоТип System.Array Для Arr
                Возврат Arr.Length=0
            КонецЕсли
            Возврат Ложь
        Иначе
            ВызватьИсключение "Функция "+ИмяФункции+" не определена."
        КонецВыбора
    КонецФункции 

    //---------------------------
    Функция ОператорБезОперандов(ИмяФункции тип Строка) тип Объект 
        Выбор Для ИмяФункции
        Когда "текущаядата" Возврат ТекущаяДата()
        Когда "текущаяуниверсальнаядатавмиллисекундах"  Возврат ТекущаяУниверсальнаяДатаВМиллисекундах()
        Когда "текущаяуниверсальнаядата"  Возврат ТекущаяУниверсальнаяДата()
        Когда "каталогвременныхфайлов"    Возврат КаталогВременныхФайлов()
        Когда "каталогпрограммы"          Возврат КаталогПрограммы()
        Когда "каталогдокументов"         Возврат КаталогДокументов()
        Когда "получитьразделительпути"   Возврат ПолучитьРазделительПути()
        Когда "сигнал" Тогда    
            Сигнал()
            Возврат Неопределено
        Иначе
            ВызватьИсключение "Функция "+ИмяФункции+" не определена."
        КонецВыбора
    КонецФункции 
    
    //---------------------------
    Функция ОшибкаЕслиОперандовНеРавно(НадоОперандов тип Целое, ЕстьОперандов тип Целое, ИмяФункции тип Строка) тип Объект 
         Если ЕстьОперандов <> НадоОперандов
            ВызватьИсключение "Количество операндов в Функции "+ИмяФункции+" не равно "+НадоОперандов+"."
         КонецЕсли   
    КонецФункции 
    
    //---------------------------
    Функция ОшибкаЕслиОперандовБольше(НадоОперандов тип Целое, ЕстьОперандов тип Целое, ИмяФункции тип Строка) тип Объект 
         Если ЕстьОперандов > НадоОперандов
            ВызватьИсключение "Операндов в Функции "+ИмяФункции+" больше "+НадоОперандов+"."
         КонецЕсли   
    КонецФункции 
    
    //---------------------------
    Функция ОшибкаЕслиОперандовМеньше(НадоОперандов тип Целое, ЕстьОперандов тип Целое, ИмяФункции тип Строка) тип Объект 
         Если ЕстьОперандов < НадоОперандов
            ВызватьИсключение "Операндов в Функции "+ИмяФункции+" меньше "+НадоОперандов+"."
         КонецЕсли   
    КонецФункции 
    
    //---------------------------
    Функция ПроверитьЧислоОперандов(РезультатПроверки тип Булево, Имя тип Строка) тип Объект 
        Если НЕ РезультатПроверки
            ВызватьИсключение "Не верное число операндов в операторе "+ТРег(Имя)+"." 
        КонецЕсли
    КонецФункции 

#КонецОбласти   

      
КонецПрограммы    

//==========================================================================================
#Область ВспомогательныеКлассы

Делегат Функция ФункцияСМассивомОперандов(ИмяФункции тип Строка, Операнды тип Объект[]) тип Объект  
Делегат Функция ФункцияСТремяОперандами(ИмяФункции тип Строка, Операнд1 тип Объект, Операнд2 тип Объект, Операнд3 тип Объект) тип Объект
Делегат Функция ФункцияСДвумяОперандами(ИмяФункции тип Строка, Операнд1 тип Объект, Операнд2 тип Объект) тип Объект
Делегат Функция ФункцияСОднимОперандом(ИмяФункции тип Строка, Операнд тип Объект) тип Объект
Делегат Функция ФункцияБезОперандов(ИмяФункции тип Строка) тип Объект

//окружение хранит список действий и переменных
//***************************
Класс клОкружение 
    Поле _Окружение тип Структура = Новый Структура
    Поле _ВнешнееОкружение тип клОкружение
    //---------------------------
    &ВидноВсем 
    Конструктор(ВнешнееОкружение тип клОкружение = Неопределено)
        _ВнешнееОкружение = ВнешнееОкружение
    КонецКонструктора
    //---------------------------
    &ВидноВсем 
    Конструктор(Идентификаторы тип Строка[], Действия тип Объект[], ВнешнееОкружение тип клОкружение = Неопределено)
        Кво = Мин(Идентификаторы.Количество,Действия.Количество)
        Для Инд=0 По Кво-1
            _Окружение.Добавить(НРег(Идентификаторы[Инд]),Действия[Инд])
        КонецЦикла
        Если Идентификаторы.Количество > Действия.Количество
            //поддержим возможность передавать в функцию меньше параметров, чем задано в её определении 
            Для Инд=Кво По Идентификаторы.Количество-1
                _Окружение.Добавить(НРег(Идентификаторы[Инд]),Неопределено)
            КонецЦикла
        ИначеЕсли Идентификаторы.Количество < Действия.Количество
            //а вот лишние параметры это ошибка
            ВызватьИсключение "Число реальных параметров функции больше, чем формальных."
        КонецЕсли
        _ВнешнееОкружение = ВнешнееОкружение
    КонецКонструктора
    //---------------------------
    &ВидноВсем 
    Конструктор(Идентификаторы тип клСписок, Действия тип Объект[], ВнешнееОкружение тип клОкружение = Неопределено)
        Кво = Мин(Идентификаторы.Количество,Действия.Количество)
        Для Инд=0 По Кво-1
            _Окружение.Добавить(НРег(Идентификаторы.ПоИндексу(Инд)),Действия[Инд])
        КонецЦикла
        Если Идентификаторы.Количество > Действия.Количество
            //поддержим возможность передавать в функцию меньше параметров, чем задано в её определении 
            Для Инд=Кво По Идентификаторы.Количество-1
                _Окружение.Добавить(НРег(Идентификаторы.ПоИндексу(Инд)),Неопределено)
            КонецЦикла
        ИначеЕсли Идентификаторы.Количество < Действия.Количество
            //а вот лишние параметры это ошибка
            ВызватьИсключение "Число реальных параметров функции больше, чем формальных."
        КонецЕсли
        _ВнешнееОкружение = ВнешнееОкружение
    КонецКонструктора
    //---------------------------
    &ВидноВсем 
    Процедура ДобавитьДействие(Идентификатор тип Строка, Действие тип Объект)
        _Окружение.Добавить(НРег(Идентификатор),Действие)
    КонецПроцедуры
    //---------------------------
    &ВидноВсем 
    Процедура ДобавитьДействие(Идентификатор тип клИдентификатор, Действие тип Объект)
        _Окружение.Добавить(Идентификатор.ИД,Действие)
    КонецПроцедуры
    //---------------------------
    &ВидноВсем 
    Функция НайтиОкружение(Идентификатор тип Строка) тип клОкружение
        Если _Окружение.СодержитКлюч(НРег(Идентификатор)) Тогда
            Возврат ЭтотОбъект
        ИначеЕсли _ВнешнееОкружение Это Неопределено
            Возврат Неопределено
        КонецЕсли
        Возврат _ВнешнееОкружение.НайтиОкружение(Идентификатор)
    КонецФункции    
    //---------------------------
    &ВидноВсем 
    Функция НайтиОкружение(Идентификатор тип клИдентификатор) тип клОкружение
        Если _Окружение.СодержитКлюч(Идентификатор.ИД) Тогда
            Возврат ЭтотОбъект
        ИначеЕсли _ВнешнееОкружение Это Неопределено
            Возврат Неопределено
        КонецЕсли
        Возврат _ВнешнееОкружение.НайтиОкружение(Идентификатор)
    КонецФункции    
    //---------------------------
    &ВидноВсем 
    Функция ПолучитьДействие(Идентификатор тип Строка) тип Объект
        Возврат _Окружение.Получить(НРег(Идентификатор))
    КонецФункции    
    //---------------------------
    &ВидноВсем 
    Функция ПолучитьДействие(Идентификатор тип клИдентификатор) тип Объект
        Возврат _Окружение.Получить(Идентификатор.ИД)
    КонецФункции    
    //---------------------------
    &ВидноВсем 
    Процедура ВставитьДействие(Идентификатор тип Строка, Действие тип Объект)
        _Окружение.Вставить(НРег(Идентификатор), Действие)
    КонецПроцедуры    
    //---------------------------
    &ВидноВсем 
    Процедура ВставитьДействие(Идентификатор тип клИдентификатор, Действие тип Объект)
        _Окружение.Вставить(Идентификатор.ИД, Действие)
    КонецПроцедуры    
КонецКласса

//встроенная в язык функция
//***************************
Класс клВстроеннаяФункция
    &ВидноВсем 
    Поле Имя тип Строка
    &ВидноВсем 
    Поле ДелегатФункции тип Объект
    //---------------------------
    &ВидноВсем 
    Конструктор(пИмя тип Строка, пДелегатФункции тип Объект)
        Присвоить Имя, ДелегатФункции = пИмя, пДелегатФункции
    КонецКонструктора
КонецКласса

//функция определяемая пользователем
//***************************
Класс клФункцияПользователя
    &ВидноВсем 
    Поле ИдентификаторыПараметров тип клСписок
    &ВидноВсем 
    Поле ТелоФункции тип Объект
    &ВидноВсем 
    Поле Окружение тип клОкружение
    //---------------------------
    &ВидноВсем 
    Конструктор(пИдентификаторыПараметров тип клСписок, пТелоФункции тип Объект, пОкруж тип клОкружение)
        Присвоить ИдентификаторыПараметров, ТелоФункции, Окружение = пИдентификаторыПараметров, пТелоФункции, пОкруж
    КонецКонструктора
КонецКласса

//список хранит элементы находящиеся в круглых скобках и в типе данных Список
//***************************
Класс клСписок 
    
    &ВидноВсем 
    Поле ПозицияВТексте тип Строка
    
    &ВидноВсем 
    Поле Данные тип Массив = Новый Массив
    
    //это оптимизация, при удалении первого элемента его место физически остается, 
    //что бы не надо было копировать весь массив на один индекс вверх 
    Поле Смещение тип Целое = 0
    
    &ВидноВсем 
    Конструктор() 
    КонецКонструктора    
    
    &ВидноВсем 
    Конструктор(МассивСтрок тип Строка[]) 
        Данные.ДобавитьВсе(МассивСтрок)
    КонецКонструктора    
    
    &ВидноВсем 
    Конструктор(МассивСтрок тип Массив) 
        Данные.ДобавитьВсе(МассивСтрок)
    КонецКонструктора    
    
    &ВидноВсем
    Процедура ВКонец(Значение тип Объект)
        Данные.Добавить(Значение)    
    КонецПроцедуры
    
    &ВидноВсем
    Функция ПоИндексу(Индекс тип Целое) тип Объект 
        Возврат Данные.Получить(Индекс+Смещение)
    КонецФункции 
    
    &ВидноВсем
    Функция ПоИндексу(Индекс тип Целое, Значение тип Объект) тип Объект 
        Данные.Установить(Индекс+Смещение,Значение)
        Возврат Неопределено
    КонецФункции 
    
    &ВидноВсем
    Функция Извлечь(Индекс тип Целое) тип Объект 
        Если Индекс=0
            Элемент = Данные.Получить(Смещение)
            Данные.Установить(Смещение,Неопределено) 
            Смещение=Смещение+1
        Иначе
            Элемент = Данные.Получить(Индекс+Смещение)
            Данные.Удалить(Индекс+Смещение)
        КонецЕсли
        Возврат Элемент
    КонецФункции 
    
    &ВидноВсем
    Функция БезПервогоЭлемента(Кво тип Целое = 1) тип клСписок 
        НовСпис=Новый клСписок(Данные)
        НовСпис.ПозицияВТексте=ПозицияВТексте
        Для Инд = 1 По Кво
            НовСпис.Данные.Установить(Смещение+Инд-1,Неопределено)
        КонецЦикла
        НовСпис.Смещение=Смещение+Кво
        Возврат НовСпис
    КонецФункции 
    
    &ВидноВсем
    Функция ФункЛев(Кво тип Целое = 1) тип клСписок 
        НовСпис=Новый клСписок(Данные)
        НовСпис.ПозицияВТексте=ПозицияВТексте
        НовСпис.Смещение=Смещение
        //???????? это можно использовать для повышения эффективности, только надо корректно обработать Кво=0 и Кво>=Количество
        //НовСпис.Данные.УдалитьДиапазон(Кво+Смещение,НовСпис.Данные.Количество-Кво-Смещение)
        Для Инд=НовСпис.Данные.Количество-1 По Кво+Смещение Шаг -1
            НовСпис.Данные.Удалить(Инд)
        КонецЦикла
        Возврат НовСпис
    КонецФункции 
    
    &ВидноВсем
    Функция ФункПрав(Кво тип Целое = 1) тип клСписок 
        НовСпис=Новый клСписок
        НовСпис.ПозицияВТексте=ПозицияВТексте
        Инд=Данные.Количество-Кво
        Если Инд<Смещение
            Инд=Смещение
        КонецЕсли
        Для Инд По Данные.Количество-1
            НовСпис.ВКонец(ПоИндексу(Инд))
        КонецЦикла
        Возврат НовСпис
    КонецФункции 
    
    &ВидноВсем
    Функция ФункСред(НачНом тип Целое = 1, Кво тип Целое = -1) тип клСписок 
        Если Кво<0
            Возврат ФункПрав(Данные.Количество-НачНом+1)
        Иначе
            НовСпис=Новый клСписок
            НовСпис.ПозицияВТексте=ПозицияВТексте
            Если Кво>0
                НачИнд=НачНом-1+Смещение
                Для Инд=НачИнд По Мин(НачИнд+Кво,Данные.Количество)-1
                    НовСпис.ВКонец(ПоИндексу(Инд))
                КонецЦикла
            КонецЕсли
            Возврат НовСпис
        КонецЕсли
    КонецФункции 
    
    &ВидноВсем
    Функция Количество() тип Целое 
        Возврат Данные.Количество-Смещение
    КонецФункции 
    
КонецКласса

//идентификатор хранит имя действия  
//***************************
Класс клИдентификатор

    //можно серьезно увеличить производительность, 
    //если полностью отказаться от имен идентификаторов и перейти на хеш-коды
    //??????? НЕ РЕАЛИЗОВАНО ????????
    
    &ВидноВсем, ОбщийДляКласса 
    Поле Счетчик тип Бит64 = 1000 //коды до 1000 зарезервированы для внутренних нужд    

    //к сожалению, некоторые внешние библиотеки регистрозависимы (например, mono) 
    //и им надо передавать идентификатор с учетом регистра 
    Поле _ИД_Оригинал тип Строка //в регистре заданном пользователем   
    Поле _ИД тип Строка          //в нижнем регистре
    
    &ВидноВсем 
    Поле _Код тип Целое    

    &ВидноВсем 
    Конструктор(ИД тип Строка)
        _ИД_Оригинал=ИД
        _ИД=НРег(ИД)
        _Код=ПолучитьКод()
    КонецКонструктора    
    
    &ВидноВсем
    Функция Код() тип Целое 
        Возврат _Код
    КонецФункции 
    
    &ВидноВсем
    Функция ИД() тип Строка 
        Возврат _ИД
    КонецФункции 
    
    &ВидноВсем
    Функция ОригиналИД() тип Строка 
        Возврат _ИД_Оригинал
    КонецФункции 
    
    //переопределим функцию преобразования к строке
    &ВидноВсем, Переопределение
    Функция ToString() тип Строка 
        Возврат _ИД
    КонецФункции 
    
    //экономия на кодах вместо идентификаторов добавляет около 5% производительности
    Функция ПолучитьКод() тип Целое 
        Если Найти(_ИД,".")>0 //вызов методов объектов
            Возврат -1 
        ИначеЕсли Найти(_ИД,":")>0 и _ИД<>":" //конвеер функций 
            Возврат -2 
        КонецЕсли
    
        Выбор Для _ИД 
        Когда "вывод","сообщить" Возврат 1                 
        Когда "перем"            Возврат 2     
        Когда "идент"            Возврат 3
        Когда "если"             Возврат 4     
        Когда "продолжить"       Возврат 5 
        Когда "прервать"         Возврат 6 
        Когда "цикл"             Возврат 7    
        Когда "пока"             Возврат 8     
        Когда "для"              Возврат 9    
        Когда "длякаждого"       Возврат 10           
        Когда "попытка"          Возврат 11       
        Когда "новый"            Возврат 12     
        Когда "++","--"          Возврат 13
        Когда "окружение"        Возврат 14         
        Когда "функ"             Возврат 15     
        Когда "функция"          Возврат 16        
        Когда "импортимен","импортимён" Возврат 17 
        Когда "загрузитьсборку"  Возврат 18 
        Когда "массив"           Возврат 19
        Когда "пауза"            Возврат 20
        Когда "очистить"         Возврат 21
        Когда "отладка"          Возврат 22 
        Когда "ввод"             Возврат 23    
        Когда "список"           Возврат 24      
        Когда "оэл","остальныеэлементы" Возврат 25                  
        Когда "кромепервого"     Возврат 26                  
        Когда "кромепервых"      Возврат 27            
        Когда "повсем"           Возврат 28      
        Когда "покаждому"        Возврат 29        
        Когда "пуск"             Возврат 30 
        Когда "уст"              Возврат 31   
        Когда "сброс"            Возврат 32     
        Когда "код"              Возврат 33     
        Когда "вычислить"        Возврат 34     
        Когда "выбор"            Возврат 35     
        Когда "возврат"          Возврат 36     
        Когда "вызватьисключение" Возврат 37     
        Когда "поумолчанию"      Возврат 38     
        
        КонецВыбора
        
        
        //??????? НЕ РЕАЛИЗОВАНО ????????
        //Счетчик = Счетчик+1;
        //Возврат Счетчик
        
        Возврат 0
    КонецФункции 
    
КонецКласса

#КонецОбласти      


К началу статьи


Вернуться в раздел:
Примеры по языку Перфо

Перейти в раздел:
Примеры
  Поддержи проект!

Вы можете поддержать разработку Перфоленты, перечислив любую удобную сумму, которая пойдет на развитие языка и поддержку инфраструктуры сайта.

  Новости:
      21.01.2026 На сайт добавлена статья "Конструируем класс. События"
      20.01.2026 Опубликован новый релиз 0.4.18.0_NY языка программирования Перфолента.Net
      29.12.2025 Анонс: Новая возможность - разрабатываем веб-сайты, веб-приложения и веб-API на Перфоленте!
      07.06.2025 Небольшие дополнения к документации на сайте - описание атрибута поля &Атомарное
      09.05.2025 На сайте опубликован релиз 0.4.16.0_SE дистрибутива языка программирования Перфолента.Net
      27.04.2025 Дополнена статья про циклы
      04.01.2025 Опубликован новый релиз дистрибутива языка программирования Перфолента.Net версии 0.4.15.0_CE
      23.09.2024 Опубликована новая статья: "Конструируем класс. Делегаты."
      30.08.2024 Опубликован новый релиз дистрибутива языка программирования Перфолента.Net версии 0.4.14.0
      24.05.2024 Обновлён справочный раздел сайта
      01.07.2023 Новая версия 0.4.13.0 языка программирования Перфолента.Net
       Все новости