Новость из категории: Информация

Взаимодействие ChaiScript с C++: контейнеры, модули и многопоточность

Содержание:
1. Идеология взаимодействия ChaiScript и С++ и язык ChaiScript;
2. Контейнеры, модули и многопоточность (Вы читаете данный раздел).
Возврат значений и регистрация контейнеров

Взаимодействие ChaiScript с C++: контейнеры, модули и многопоточность

Чтобы в основной программе на С++ получить из интерпретатора ChaiScript какое-то значение, используется метод eval:
ChaiScript chai;
cout << chai.eval("1+3") << endl; // Печатает 4

Из интерпретатора можно получать указатели на объявленные там функции (даже анонимные):
chai("var f = fun(a,b){a+b}"); // Создаем функцию в ChaiScript
// Получаем указатель на нее
boost::function f = chai.eval("f");
cout << f(2,5) << endl; // Вызываем функцию в С++

Идиллия заканчивается, когда приходится возвращать из ChaiScript векторы:
chai("vec = [1,2,3,4]");
vector vec = chai.eval >("vec");
terminate called after throwing an instance of 'chaiscript::exception::bad_boxed_cast'
what(): Cannot perform boxed_cast

Проблема легко объяснима: вектор в ChaiScript - это vector, а нам нужен vector.

Для С++ это совершенно разные типы, а преобразовать один в другой можно только поэлементно, что очень трудоемко. У этой проблемы есть простое решение - зарегистрировать в интерпретаторе тип vector.

Для этого даже есть специальная функция:
chai.add(bootstrap::standard_library::vector_type
< std::vector >("Vector_int"));
chai("var vec1 = Vector_int()"); chai("vec1.push_back(11)");
vector vec1 = chai.eval >("vec1"); // Работает!

Таким образом можно добавлять векторы любых объектов. Также есть аналогичные функции map_type для типов std::map и list_type для std::list. При этом, к сожалению, теряется удобный синтаксис инициализации массивов на лету.

Рассмотренная выше функция bootstrap::standard_library::vector_type и примеры ее использования в документации нигде не описаны. Ее можно «откопать» только в аннотациях к исходных кодам и на форуме. И для ChaiScript это обычная ситуация...

Ценным источником информации в таких случаях являются юнит-тесты ChaiScript в директории unittests. Просматривая их можно, например, узнать, что в ChaiScript существуют довольно развитые средства интроспекции и отображения, которые также никак не документированы.

Модули и многопоточность

Интерпретатор ChaiScript может без проблем вызываться из разных потоков, если при компоновке используется библиотека Boost.thread. Пример такого вызова находится в файле src/ multithreaded.cpp.

В многопоточном режиме интерпретатор работает медленнее, но на практике это обычно не заметно, поскольку всё равно все вызовы переадресовываются функциям С++. Реализацией многопоточности ChaiScript выгодно отличается от других встраиваемых языков. В отличие, например, от Python в ChaiScript нет собственных средств для запуска потоков, но каждый поток родительской программы может свободно вызывать любые команды интерпретатора, не опасаясь накладок и не предпринимая никаких специальных действий для защиты данных в скрипте.

Одной из потенциально полезных возможностей ChaiScript являются динамически загружаемые модули. Именно для них при компоновке в Linux необходима библиотека ldl. В скрипте можно во время выполнения загружать специальным образом созданные динамические библиотеки, используя функцию load_module("имя модуля").

Модуль в ChaiScript - это лишь вынесенный в динамическую библиотеку набор функций; он не создает новое пространство имен как в уже упомянутом Python. Чтобы создать простейший модуль, нужно написать примерно такой код:
#include #include #include
void hello_module(){
std::cout << "Hello from my_module!" << std::endl;
}
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_my_module()
{
chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_module), "hello_module");
return m;
}

Все достаточно интуитивно понятно: модуль экспортирует одну функцию hello_module, а макрос CHAISCRIPT_MODULE_EXPORT отвечает за всю внутреннюю «бухгалтерию». Однако добиться того, чтобы скомпилированный модуль загружался в интерпретатор, оказалось не так-то простым делом . Методом проб и ошибок удалось выяснить два критичных момента.

Во-первых, в строке:
create_chaiscript_module_my_module()

обязательным префиксом является «create_chaiscript_module_», а всё последующее - это собственно имя модуля.

Во-вторых, имя получаемой библиотеки должно быть lib.so (в нашем случае libmy_module.so). У меня в 64-битной Ubunu 11.10 успешной оказалась компиляция с такими флагами:
$ g++ -fPIC -Кпуть к ChaiScript> -o my_module.o -c my_module.cpp
$ g++ -fPIC -shared -o libmy_module.so -ldl my_module.o

Проверить модуль можно так:
$ ./chai -c 'load_module("my_module"); hello_module()'

На экране появится «Hello from my_module!». Модули позволяют разбить программу на независимые компоненты, которые можно по мере надобности загружать прямо из скриптов, не теряя при этом в скорости.

Выводы

ChaiScript, безусловно, язык не для всех. Хотя бы потому, что он не является самодостаточным, как Python или Ruby. Идейно он больше всего напоминает браузерный javascript, который бесполезен в отрыве от самого браузера (Впрочем, активное распространение Node.js стремится исправить эту ситуацию. - Прим. ред.), но в то же время делает браузеры чрезвычайно мощными инструментами. ChaiScript намертво привязан к С++, и в этом его основная сила. Встраивание полноценного интерпретатора в любую программу на С++ занимает несколько минут (в простейших случаях) и даже не требует никакой дополнительной компоновки со сторонними библиотеками.

Сама идея языка, который полностью полагается на типы данных родительской программы, кажется мне по-настоящему революционной. Печально известный бич всех скриптовых языков - преобразование данных между компилируемым бекэндом и скриптовым фронтэн-дом. В ChaiScript просто нечего преобразовывать: всё, что надо скрипту, объявляется на С++ и регистрируется в интерпретаторе.

Есть у ChaiScript и недостатки. Язык слишком прост, в нем нет полноценных классов, пространств имен, замыканий, внятной стандартной библиотеки. Документация, мягко говоря, неполна и организована не лучшим образом. Тем не менее, ChaiScript может быть идеальным вариантом для проектов на С++, где нужно «малой кровью» реализовать скриптовый язык и нет потребности в самодостаточных языках, таких как Python или Lua.

Рейтинг статьи

Оценка
0/5
голосов: 0
Ваша оценка статье по пятибальной шкале:
 
 
   

Поделиться

Похожие новости

Комментарии

^ Наверх