дублер каскадера АЛЕКСАНДР ГЛАДЫШ Спецвыпуск: Хакер, номер #071, стр. 071-068-9 end ) end end Здесь стандартная функция string.gsub используется для замены всех вхождений «$(имя_переменной)» на значение этой переменной в переданной вторым параметром таблице-контексте. Пример использования, печатающий текущую дату: local str = smart_str “Today is $(date)” { date = os.date() } print(str) Подробно возможности встроенного языка регулярных выражений описаны в руководстве по языку Lua. Иногда бывает необходим больший, чем может дать приведенная реализация smart_str, контроль над кодогенерацией. Например, нужно использовать циклы или условные переходы. Можно пойти по пути усложнения синтаксиса, поддерживаемого этой функцией. Однако есть другой способ, родственный «наивному» подходу генерации строк, когда код просто «подклеивается» к строке с результатом. Так как строки в Lua неизменяемы, код, подобный следующему, весьма неэффективен (он засоряет память промежуточными значениями result): local result = ‘return {‘ for i = 1, 1000 do result = result .. math.random() .. ‘;’ end result = result .. ‘}’ Значительно более эффективно во время генерации сохранять строки в таблице, а после генерации склеить их при помощи стандартной функции table.concat. После некоторой доработки получаем второй способ кодогенерации: local strings = { } local i = 1 local _ = function(val) strings[i] = tostring(val); i = i + 1 end _ ‘return {‘ for i = 1, 1000 do _ (math.random()) _ ‘;’ end _ ‘}’ local result = table.concat(strings) В не слишком запущенных случаях этот способ позволяет писать достаточно наглядный код, одинаково хорошо показывающий как шаблон генерируемого кода, так и логику генерации. Но в тяжелых случаях со сложной логикой генерации помочь может только реализация «объектной модели» кода Lua (code document ob-ject model). Рассмотрим, как можно организовать генерацию кода для нашего случая с пользовательским интерфейсом. Пойдем по простейшему пути. Запускаем обход от самого нижнего элемента подобно листингу 2. Каждый элемент возвращает строку, которую нужно «подклеить» к общему коду. Функцию process_child_keywords заменяем на функцию concat_child_keywords, конкатенирующую («сцепленные») строки, полученные от всех дочерних ключевых слов. concat_child_keywords = function(data) local strings = { }; local i = 1 for _, child in ipairs(data) do if type(child) == “function” then strings[i] = child(data); i = i + 1 end end return table.concat(strings) end hidden = function(dest) dest.visible = false; return “” end panel= name_data(“panel”) function(name, data) local create_children = concat_child_keywords(data) if data.visible == nil then data.visible = true end if data.modal == nil then data.modal = false end return smart_str ( ‘do local wnd=Window.Create($(name),parent_wnd,$(modal));’ .. ‘wnd:SetVisible($(visible))’ .. ‘parent_wnd= ush_parent_wnd(wnd);’ .. ‘$(create_children);’ .. ‘parent_wnd=pop_parent_wnd(wnd);end;\n’ ) { name = ‘”’ .. name .. ‘”’; modal = data.modal; visible = data.visible; create_children = create_children; } end end) БЕЗ КОНКРЕТНОГО ФОРМАТА |