LINUX.ORG.RU

Как правильно писать кодогенераторы?

 ,


3

4

Я про то, что хочется шляпу наговнокодить, которая LUA код сама будет редактировать в скрипте, структуру которого я знаю перетаскиванием ползунков, чтобы мозг не выносить тысячами параметров. Говнокодить генератор хочу на питоне. Есть какая теория, чтобы весь проект не был похож на монстров Лавкрафта и с ним было более-менее удобно работать? Никогда такого ежа с носорогом не пробовал скрещивать...

Советов от тех кто что-то похожее писал хочу услышать до того, как начну процесс ковыряния в субботу.

★★★★★

Последнее исправление: peregrine (всего исправлений: 2)

Из всего этого я понял, что у тебя есть ползунки где-то в питоне, и ты хочешь из них генерировать код на луа. Не думаю, что под это описание вообще может быть какая-то теория.

anonymous
()

структуру которого я знаю перетаскиванием ползунков

что-то у тебя сериализатор мыслей барахлит.

Tanger ★★★★★
()

Бухой был?
Ничего же не понять из того, что хочешь сделать …

anonymous
()

Как правильно писать кодогенераторы?

Попроси совета у великого кодогенератора - Метапрог.

anonymous
()
Ответ на: комментарий от Tanger

Есть такое. Думаю сериализатор мыслей к субботе починится, немного устал, простудился (вроде не коронка, тест отрицательный пока) и бессонница спать толком не даёт. Засыпаю, сплю 3-4 часа и просыпаюсь. Вот после предыдущего коммента уснул сразу почти, а сейчас проснулся опять. Если повезёт, то смогу днём ещё поспать.

Идея в следующем — попробовать для себя сделать генератор объектов с рецептами из minetest-а, хочу чтобы на основании названия текстурок вида modname_itemname.png и текстурок вида modname_itemname_up.png и так далее генерировать обе функции, если есть текстурки с up, down и так далее, ну а дальше ручками описание вносить (часть текстурок генерируется (да хочу и могу), так что есть возможность делать наименования без ошибок):

minetest.register_craftitem("modname:itemname", {
    description = "",
    inventory_image = "modname_itemname.png"
})
minetest.register_node("modname:name", {
    description = "",
    tiles = {
        "modname_name_up.png",    -- y+
        "modname_name_down.png",  -- y-
        "modname_name_right.png", -- x+
        "modname_name_left.png",  -- x-
        "modname_name_back.png",  -- z+
        "modname_name_front.png", -- z-
    },
    is_ground_content = ,
    groups = {},
    drop = ""
})
Это избавит от рутины и ошибок наименования с потерей текстурок, остальные параметры description, is_ground_content = , groups = {}, drop = «» ручками вписывать, а при повторном запуске скрипта проверять их наличие и не сбрасывать, если не пусто, но это уже меньше возни и шансов на ошибку. Ну и разумеется срать в консольку, если modname_name_back.png отсутствует, а modname_name_front.png есть.

peregrine ★★★★★
() автор топика
Последнее исправление: peregrine (всего исправлений: 2)

Я знаю два подхода.

  1. Берешь шаблон (строку) и форматируешь по словарю с параметрами. Это самый простой вариант. Можно изголится и в шаблоне вводить свои спецификаторы вывода, а на вход подавать объект эмулирующий словарь который эти спецификаторы отрабатывает.

  2. Разбираешь питоний код в AST, меняешь то что нужно (если нужно) и выводить в нужном формате.

Можно эти два варианта комбинировать в разных пропорциях

AntonI ★★★★
()
Ответ на: комментарий от peregrine

Если будут вопросы про разбор в AST, пиши. Хотя это скорее для компьютерной алгебры подход (ну или когда на вход пришло арифметическое выражение в одном формате, а тебе его надо кастануть в другой формат).

AntonI ★★★★
()

Поставь перед этими параметрами специального вида многострочные комментарии.

do_stuff(--[[param name=myvar type=int min=0 max=10]] 0)

Впрочем, вероятно способ не подойдёт.

чтобы весь проект не был похож на монстров Лавкрафта

Ceiling_QB ★★★★
()
Последнее исправление: Ceiling_QB (всего исправлений: 1)
Ответ на: комментарий от monk

О, спасибо большое. Пойду читать.

peregrine ★★★★★
() автор топика
Ответ на: комментарий от peregrine

лучше писать некий хедер с максимально простой структурой и потом уже инклудить в большой скрипт где и конструировать объекты (в цикле).

slapin ★★★★★
()

Надо просто сгеатанагашп

anonymous
()

Посмотри на чтото типа COG - сэкономишь много времени и усилий

cvv ★★★★★
()
Ответ на: комментарий от peregrine

Царь не является адептов крестов - адепт врёт. Он признаёт только gnuc и gnu++ актуальный настоящему времени(где-то от 18-19 года и старше). Никакой си, а уж тем более C++ царь никогда не признавал и определял за дерьмо и дерьмо дерьма, соответственно.

anonymous
()
Ответ на: комментарий от peregrine

Зачем тебе какой-то генератор? У тебя логика никак не меняется - меняются картинки. Ну и подставляй их названия в одну и ту же функцию.

Показанная тобою дристня так и работает. И непонятно что ты хочешь от генератора

anonymous
()

Советов от тех кто что-то похожее писал

На шелле собирал рекурсивные SQL-запросы, например.

anonymous
()
Ответ на: комментарий от peregrine

И что? Читай эти картинки и заполняй конфигурацию. У тебя там reg_dristnya(a, b, c, d, ...). Вот читаешь картинку dristnya1.png, вычленяешь её из базу - dristnya1, а далее к ним прибавляешь свои суфиксы или что там у тебя. Получается так reg_dristnya("dristnya1.png", "dristnya1_up.png", "dristnya1_down.png", ...).

Тебе просто нужно собрать аргументы для вызова функции, где аргументы - это имена твоих картинок. Тебе никакая кодогенерация не нужна. Ну по крайней мере для той задачи, которую ты описал.

anonymous
()
Ответ на: комментарий от anonymous

Есть Urn, недолисп на Lua, собирается в него же.

собирается в него же.

В урну, что ли?

Плюс есть Fennel.

theNamelessOne ★★★★★
()
Ответ на: комментарий от anonymous

А как с проверкой быть тогда? Мне удобнее чтобы не в чатике майнтеста отладку вести, о том что у блока стороны не хватает или ещё что-нибудь... Как бы майнтест не IDE.

peregrine ★★★★★
() автор топика
Ответ на: комментарий от peregrine

А как тебе ide поможет? Особенно в пистоне.

Ну нагенерь лапши - всё тоже самое, только reg замени на ген. Реализация там примитивная:

(modename, itemname, name) => `
minetest.register_craftitem("${modname}:${itemname}", {
    description = "",
    inventory_image = "${modname}_${itemname}.png"
})
minetest.register_node("${modname}:${name}", {
    description = "",
    tiles = {
        "${modname}_${name}_up.png",    -- y+
        "${modname}_${name}_down.png",  -- y-
        "${modname}_${name}_right.png", -- x+
        "${modname}_${name}_left.png",  -- x-
        "${modname}_${name}_back.png",  -- z+
        "${modname}_${name}_front.png", -- z-
    },
    is_ground_content = ,
    groups = {},
    drop = ""
})
`

В твоём же пистоне есть интерполяция/принтф? Либо возьми шаблонизатор как предлагали пацаны. Сливаешь всё это в файл и пусть там твоя ide чекает валидность инициализаторов.

Просто ты нормально не описал что тебе надо. И до сих пор нихрена не понятно.

anonymous
()
Ответ на: комментарий от anonymous

Ну нормально я в субботу только смогу написать, тогда давай до той поры отложим, ну или я шаблонизатором обмажусь и мне его с головой хватит.

peregrine ★★★★★
() автор топика

Я 9 лет использую кодогенерацию в своих проектах на C/C++, в конкретной моей нише это очень востребовано. Начинал со строк-шаблонов на C, через два года дошёл до связки Python + Cog.

Cog уже рекомендовали и, насколько я знаю, ничего лучше пока что нет. Как это работает - у автора на сайте есть примеры. Можно смешивать код генератора на питоне с файлом, в котором будет сгенерированный код, можно питоновский код писать в отдельном файле и импортировать внутри генерируемого. Делаешь функцию, у неё параметры - значения твоих ползунков, она генерирует нужный код. Может при этом делать что угодно, хоть лезть в интернет за курсом валют, хоть смотреть какие есть файлы с текстурами. После Cog я на шаблоны смотрю с усмешкой. Кодогенерация - недооценённая технология. И Cog позволяет использовать её по-настоящему.

tim239 ★★
()
Ответ на: комментарий от tim239

Какая же нелепая херня. Прям квинтэссенция бездарности. Пистон, скриптуха в комментах, printf для генерации.

Осталось только понять - зачем вообще нужно это дерьмо? Оно ведь ничего не делает. Ну для учеников начальных классов наверное покатит.

После Cog я на шаблоны смотрю с усмешкой.

Какое отношение это дерьмо имеет к шаблонам? Там в качестве шаблонов используется printf. Очевидно, что шаблоны как раз таки и созданы для того, чтобы решить его проблемы.

Кодогенерация - недооценённая технология.

Где там кодогенерация? Это бездарная пародия на пхп.

И Cog позволяет использовать её по-настоящему.

А, ну если по настоящему. Там в яслях настолько кодогенерация настоящая, что адепты не знаю даже о том, что это вообще такое.

anonymous
()
Ответ на: комментарий от anonymous

насчёт теории: мультистадийное программирование (метапрограммирование)

Meta-programming

In this guide we’ve already encountered instances of meta-programming, such as using a Lua loop to create an array of Terra pow functions. In fact, Terra includes several operators that it make it possible to generate any code at runtime. For instance, you can implement an entire compiler by parsing an input string and constructing the Terra functions that implement the parsed code.

The operators we provide are adapted from multi-stage programming. An escape allows you to splice the result of a Lua expression into Terra. A quote allows you to generate a new Terra statement or expression which can then be spliced into Terra code using an escape. Symbol objects allow you to create unique names at compile time. Finally, a macro can be used like a function call in Terra code but will be evaluated at compile-time. We’ll look at each of these operators in detail.

из PDF по ссылке:

multi-stage programming with explicit annotations:

A Staged Program = A Conventional Program + Staging Annotations

1.4 A classic example

A staged interpreter is a translator

1.8 Meta-programming vs. Multi-stage vs. Multi-level vs. two-level

примеры на MetaOcaml, но на MetaLua или Terra тоже похоже.

ещё читай бложик металуа с примерами.

anonymous
()

хочется шляпу наговнокодить, которая LUA код сама будет редактировать в скрипте,

примеры кода нагенерированного шляпой надо бы.

anonymous
()
Ответ на: комментарий от tim239

чего только не выдумают лишь бы nim не ставить

anonymous
()
Ответ на: комментарий от peregrine

map по двум спискам, один с имёнами файлов, другой с лямбдами. лямбдами запускаются проверки и валидации, например, есть файл или нет (и срать в консольку). ну и какой-то AST pattern matching и code walker поверх всего этого. это если на общий вид с мультистадийным и аннотациями (как наиболее наглядным метапрогом) заморачиваться. если нет – то тупой шаблонизатор (по двум спискам), «как советовали пацаны», ога.

anonymous
()
Ответ на: комментарий от anonymous

структуральнейший лингвист Хомского

из MetaLua manual лучше PDF:

4.1.2 Structural pattern matching

если вот этого всего не нужно, потому что структура генерируемого на Lua кода (на объектном языке Lua, для которого MetaLua – метаязык) – относительно простая, тогда просто map по спискам + шаблонизатор. если нужно, то map по этому structural pattern matching по AST объектного языка Lua примера кода кодогенерируемого, который реализуется через code walker + библиотеку парсера объектного языка или метаязыка (gg, mlp в metalua). примеры code walker, расширения синтаксиса, квазицитирования, AST structural pattern matching там есть в мануале. или в бложике. или в terra.

anonymous
()

Зачем генерировать код? Нельзя сделать код отдельно, а отдельно конфиг файл для него, который, может быть, и генерировать?

А так может быть достаточно простого шаблонного движка (Jinja2, например).

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Может и ни в чём, разве что Cog изначально предлагался как тулза для написания исходного кода, а шаблонные движки - html-страниц. У меня обычно нет шаблона, в коде вызывается функция на питоне которая генерируют весь код. Из зависимостей - только питон и Cog.

tim239 ★★
()
Ответ на: комментарий от tim239

Может и ни в чём

Фееричный слив после заявления «ничего лучше пока что нет». Я просто не вижу ни одного плюса. Код на питоне для генерации текста слишком громоздок:

/*[[[cog
import cog
# ...откуда-то достать fnames...
for fn in fnames:
    cog.outl("void %s();" % fn)
]]]*/

vs.

{% for fn in fnames %}
void {{ fn }}();
{% endfor %}

Никакого разделения логика/представление, мешанина из нескольких языков. Ничего визуально общего с целевым кодом - нужно долго вникать чтобы понять что тут генерируются объявления функций. То что результат встраивается в тот же файл - уродство при работе с VCS.

а шаблонные движки - html-страниц

В шаблонах нет ничего специфичного для html. Шаблонизировать можно хоть sql, хоть C++, хоть json, хоть plaintext.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Ну ок, считайте что я слился. Я то имел в виду плюсовые шаблоны. Потому что начинал внедрять Cog вместо связки define’ов и шаблонов. Мне код выше - с Сog - всё равно нравится больше. Три-две строки на обычном питоне вместо мешанины из целевого кода и шаблона. Да, целевой язык при этом будет в виде строки «void %s()», ну и что? import cog достаточно объявить один раз за файл, и то не всегда он нужен. Насколько это всё будет хорошо сделано - да как сделаешь, так и будет. Мне хватает. Про VCS - можно это сохранять в сгенерённом виде, можно генерить перед сборкой или во время сборки.

tim239 ★★
()
Ответ на: комментарий от slovazap

Ты так же обгадился. Именно код - самый совершенный генератор. А шаблоны удел домохозяек. Правда к пистону это отношения не имеет.

# ...откуда-то достать fnames... - уровень идиотии зашкаливает. Откуда в твоём высере взялся fnames ты не сообщил. Почему же он должен сообщать.

Никакого разделения логика/представление, мешанина из нескольких языков.

Логика/представления - для дошколят. Правды кроме ничего не бацал - тебе сложно будет это понять.

Ничего визуально общего с целевым кодом - нужно долго вникать чтобы понять что тут генерируются объявления функций

Как и в твоём высере. К тому же, ты опять обгадился так же как и он. Твоё говно - аналог его printf"а.

К тому же, ты там же обгадился и с логикой. Потому как ты засунул for в дерьмо, а значит уже смешал логику/дошколятоставление.

В шаблонах нет ничего специфичного для html. Шаблонизировать можно хоть sql, хоть C++, хоть json, хоть plaintext.

Нельзя, ты опять обгадился. Просто пхп-макака не способна это осознать.

anonymous
()
Ответ на: комментарий от tim239

Я то имел в виду плюсовые шаблоны.

Ты о них ничего не знает.

Потому что начинал внедрять Cog вместо связки define’ов и шаблонов.

А мог выучить язык, ну по крайней мере попытаться.

Три-две строки на обычном питоне вместо мешанины из целевого кода и шаблона.

Ещё раз, ты ничего не знаешь ни о С++ ни о шаблонах. Пиши «я не смог», «я не знал», «у меня нет никакого С++ и нет никаких шаблонов».

Да, целевой язык при этом будет в виде строки «void %s()», ну и что?

То, что это могло бы выглядеть void ${name}(), вот выше есть пример. Перепиши его на принтф - многое осознаешь.

anonymous
()
Ответ на: комментарий от slovazap

Для этого нужно обладать пониманием чем большим, чем у эникея. Скоро ты дойдёшь до пхп - поймёшь.

В целом выше в своих жалких потугах ты уже частично написал чем. Написав в шаблонном дерьме логику, наличие которой ты отрицал. Но Обгадится для тебя - это норма.

Дак вот, открою тебе тайну, эникей. Шаблон не существует без логики, а значит ты не можешь сравнивать cog и шаблоны. И ты опять обгадился.

Но у вас что-то у всех проблема с этим. Но это норма для эникея, не волнуйся.

anonymous
()
Ответ на: комментарий от tim239

Ну с плюсовыми шаблонами это нельзя сравнивать, потому что говно ничего не знающее про целевой язык vs. нативный инструмент (да, недостаточно типизированный, но всё-таки не произвольный текст). Для языков где нет нативного метапрограммирования - понял, смысла тоже не имеет, хоть и могло бы.

slovazap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.