дублер каскадера АЛЕКСАНДР ГЛАДЫШ Спецвыпуск: Хакер, номер #071, стр. 071-068-6 for _, child in ipairs(data) do if type(child) == “function” then child(data) end end end Все параметризованные функции – ключевые слова, кроме корневого, можно реализовать по следующей схеме: -- Вместо keyword_name нужно подставить имя ключевого слова keyword_name = name_data(“keyword_name”) function(name, data) process_child_keywords(data) data.type_ = keyword_name data.name_ = name return function(dest) if not dest.children_ then dest.children_ = { } end table.insert(dest.children_, data) end end) В реализации унарных ключевых слов, очевидно, что нужно опустить упоминание name_data, поскольку единственный аргумент передается за один вызов функции. У корневого ключевого слова (gui_layout) не может быть предков, поэтому оно должно возвращать готовую таблицу с данными. В остальном, оно реализуется по той же схеме: gui_layout= name_data(“gui_layout”) function(name, data) process_child_keywords(data) data.type_ = gui_layout data.name_ = name return data end) Недостаточное число аргументов Приведенная выше реализация функции pipeline не позволяет эффективно обнаружить один из видов ошибок в данных – когда пользователь указывает недостаточное число аргументов для ключевого слова. Например, если для панели указано только имя: panel “bad_panel”; Как видно из его реализации, сборщик аргументов collector возвращает самого себя до тех пор, пока не наберет нужного числа аргументов. Поэтому в такой ситуации в списочной части таблицы данных ключевого слова-предка оказывается не результат работы функции – реализации ключевого слова-потомка sink, а сам сборщик. Эту ошибку можно обнаружить, сделав сборщика из функции таблицей с заданным метаметодом __call (реализацией этого метаметода будет нынешнее тело функции-сборщика) и заданным (мета)полем, обозначающим, что это – сборщик. В process_child_keywords при обнаружении таблицы вместо функции необходимо проверять значение этого поля. Если обнаружен сборщик, нужно выдавать ошибку о недостаточном количестве аргументов. Дополнительную отладочную информацию о природе сборщика (имя, типы, число аргументов) можно хранить в его же (мета)таблице. Тем же способом можно реализовать задание значений аргументов по умолчанию – вместо выдачи ошибки нужно просто вызывать сборщик с этим значением (или значениями) до тех пор, пока он не наберет достаточное количество аргументов. Если нужна поддержка значений параметров по умолчанию, их установку целесообразно вставить после обработки ключевых слов-потомков. Например, панели должны быть видимы по умолчанию, значит, для ключевого слова panel после вызова process_child_keywords нужно добавить строчку: if data.visible == nil then data.visible = true end На выходе для данных из листинга 1 будет сгенерированна примерно такая таблица (для экономии места описание панели «settings» пропущено): { type_ = “gui_layout”; name_ = “gamegui”; children_ = { [1] = { type_ = “panel”; name_ = “mainmenu”; modal = true; visible = true; children_ = { [1] = { type_ = “button”; name_ = ”newgame”; }; |