дублер каскадера АЛЕКСАНДР ГЛАДЫШ Спецвыпуск: Хакер, номер #071, стр. 071-068-5 setfenv(loader, ddl_keywords) return loader() end Использовать эту функцию можно аналогично loadfile: local data = assert(load_ddl_file(“myguilayout.lua”, ddl_keywords)) Подразумевается, что реализация ключевых слов языка находится в таблице ddl_keywords. Для большего контроля можно запретить запись в эту таблицу и чтение из нее данных по отсутствующим ключам, переопределив в ее метатаблице методы __index и __newindex. Учитывая все вышесказанное, можно перейти к обсуждению путей реализации самих функций – ключевых слов для нашего примера. [реализация.] Большинство ключевых слов требует двух вызовов для получения всех данных. В первом вызове обычно передается имя, во втором – таблица с данными. Чтобы облегчить реализацию, введем вспомогательную функцию – генератор «сборщиков данных». Функция-сборщик собирает переданные ей данные, одновременно проверяя соответствие их типов заданным. После того, как нужное количество аргументов собрано, они передаются пользовательской функции (sink): pipeline = function(name, ...) assert(type(name) == “string”) local types = {...} local nargs = #types return function(sink) local args = { } local n = nargs local collector collector = function(a) local i = 1 + nargs – n local argt = types[i] if argt ~= “any” and type(a) ~= argt then error(string.format( "%s: Bad argument %d, %s expected" name, i, types[i] )) end args[i] = a if n > 1 then n = n — 1 return collector else return sink(unpack(args)) end end return collector end end Далее зададим функции для генерации «сборщиков» аргументов заданных фиксированных типов (произвольный тип аргумента можно указать, используя в качестве имени типа слово «any»). Например, для ключевых слов, требующих аргументы по схеме «имя – данные» подойдет такая функция: name_data = function(name) return pipeline(name, “string”, “table”) end Наиболее прямолинейный способ реализации ключевых слов – просто собирать все данные в одну большую иерархическую таблицу, занося «имена» и «типы» элементов интерфейса в служебные поля таблиц данных этих элементов. Фактически, это прямое, без каких-либо дополнительных действий, преобразование «исполнимого кода», описывающего данные в сами данные. Ключевые слова без аргументов в этом и в остальных рассматриваемых случаях – функции, задающие значение определенного ключа в таблице данных. Такие функции играют роль «синтаксического сахара», повышающего наглядность. Например (dest – таблица данных для изменения): hidden = function(dest) dest.visible = false end Все ключевые слова без аргументов попадают в порядке упоминания в списочную часть таблицы данных ключевого слова-родителя. Значения, возвращенные «дочерними» ключевыми словами, также попадают в списочную часть. Для единообразия эти значения тоже можно сделать функциями, которые при вызове будут добавлять данные об элементе-потомке в специальный список, хранящийся в таблице данных элемента-родителя. Перед анализом данных родительского элемента следует сделать обход списочной части для сбора данных о потомках: process_child_keywords = function(data) |