дублер каскадера АЛЕКСАНДР ГЛАДЫШ Спецвыпуск: Хакер, номер #071, стр. 071-068-3 Конструкция foo “string” { key = “value” } эквивалентна конструкции foo(“string”)({ key = “value” }). Сначала вызывается функция foo, которой передается параметр «string». Функция foo возвращает другую (анонимную) функцию, которая вызывается с параметром-таблицей { key = “value” }. Например, реализованная следующим образом foo в этом случае выведет на экран «string value»: foo = function(str) return function(tab) print(str, tab[“key”]) end end Эти полезные особенности Lua предоставляют нам достаточно широкие возможности для реализации «самозагружающихся» описаний данных. Благодаря тому, что Lua позволяет компилировать программы в байт-код для виртуальной машины, мы можем «бесплатно» получить бинарное представление данных с еще меньшей избыточностью, к тому же снимающее затраты на парсинг и компиляцию текста (впрочем, в неэкстремальных случаях затраты на компиляцию итак достаточно невелики). Кроме того, текущая реализация языка Lua легко справляется с большими объемами данных – «пережевать» файл в несколько мегабайт для нее не проблема (конечно, при адекватной реализации пресловутой системы «самозагрузки»). Если при выполнении кода (смотри листинг 1) в области действия будут находиться реализованные должным образом функции gui_layout, panel, button и checkbox, получим набор вызовов, показанный на рисунке. Переменные modal и hidden могут содержать значения любого типа, главное, чтобы они тоже были видимы. Фактически, можно сказать, что мы видим здесь данные, записанные при помощи языка описания данных (data description language, DDL). Перечисленные имена переменных – ключевые слова (keywords) в создаваемом нами языке описания пользовательского интерфейса. Нужно заметить, что наши данные носят ярко выраженный иерархический характер. Промежуточная кодогенерация Поскольку описание данных – валидный код на Lua, мы имеем возможность, например, «разбавить» декларативное описание интерфейса кодом описания его функциональности – скажем, описать обработчики событий по клику на кнопку: panel “mainmenu” { modal; button ”newgame” { action = StartNewGame; }; button ”settings” { action = function() showpanel(“settings”) end; }; button “exit” { action = confirm(ExitGame); }; }; Конечно, если код обработчика пишется вручную, такой подход следует применять с осторожностью, всячески ограничивая API, доступный таким функциям, и проводя их максимальную проверку на корректность и безопасность. Помимо этого, наличие функций непосредственно в описании данных несколько затрудняет вариант реализации DDL с промежуточной кодогенерацией – такие обработчики придется как-то сохранять вместе со всеми данными. Например, их можно сохранять в виде байт-кода при помощи системной функции string.dump – накладываемое ограничение на отсутствие у таких функций ссылок на внешние переменные (upvalues) в данном случае не слишком существенно. |