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

Немного Теории

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

Требования

Компилятор: общие требования

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

Билдер: общие требования

  • Должен уметь запускать компилятор, передавая ему пути к исходному коду
  • Должен уметь собирать пригодную к запуску карту из папки и исходного кода
  • Должен уметь запускать дополнительные утилиты при условии их наличия
  • Должен уметь игнорировать файлы "только для редактора" при сборке релизной версии карты

Интеграция: общие требования

  • Простота настройки и начала работы
  • Все входящие в базовый комплект утилиты должны скачиваться автоматически, без необходимости ручной установки и тем более компиляции
  • Обязательные настройки перед началом работы должны сводиться к указанию путей к игре и редактору, все остальные настройки должны быть опциональными и иметь приемлемые значения по умолчанию
  • Наличие пресета пустого проекта со стандартными настройками и готовой к работе файловой структурой
  • Возможность работать в редакторе карт параллельно с редактированием кода в VSCode

Проект: общие требования

  • Представлен в виде папки
  • Одна карта - один проект
  • Содержит воркспейс VSCode
  • Содержит файлы конфигурации для конкретного проекта
  • Содержит фиксированную структуру папок, диктующую расположение элементов проекта
  • Содержит карту представленную в виде папки
  • Содержит файлы с исходным кодом
  • Содержит папку, в которую складываются промежуточные результаты и временные файлы
  • Содержит папку, в которую складывается карта после сборки
  • Все файлы находящиеся вне фиксированной структуры не влияют напрямую на происходящие в проекте процессы и формально не являются его частью

Предполагаемые фичи

Интеграция

  • Возможность отдельного запуска компилятора из VSCode
  • Возможность запуска процесса сборки карты из VSCode
  • Возможность запуска карты на тестирование из VSCode
  • Возможность открытия карты в редакторе карт по команде из VSCode
  • Возможность хранить настройки самой интеграции и всех утилит в конфигурационных файлах конкретного проекта
  • Возможность выбирать пресет по которому работают билдер и компилятор
  • Возможность применять набор твиков к исходной карте, например исправленый abilitydata.slk для отображения скрытых способностей

Компилятор

  • Преобразование равкодов в числа на этапе компиляции. Предварительно реализовано макросом RAW('A000')
  • Инлайн переменных и функций. Предварительно частично реализовано макросом --#INLINE для переменных
  • Генерация отладочной информации, позволяющей найти строку в файлах исходного кода по номеру строки в итоговом коде
  • Режим компиляции release. Из кода исключаются фрагменты не нужные в релизной версии карты, а также код карты подвергается минификации
  • Режим компиляции dev. Предназначен для быстрого запуска карты в близком к релизному виде, но с сохранением структуры кода.
  • Режим компиляции debug, в код карты добавляются дополнительные отладочные элементы. Предназначен для поиска причин возникновения ошибок ценой потенциальной потери производительности.
  • Макросы, позволяющие отмечать фрагменты кода соответствующие различным режимам компиляции

Биллдер

  • Несколько режимов работы, отличающихся передаваемыми другим утилитам настройками
  • Режим release - карта максимально очищается от лишних и не обязательных файлов, код компилируется в релизном режиме,возможен запуск внешних оптимизаторов.
  • Режим dev - карта собирается в близком к релизному виде, но с применением только минимального набора оптимизаций.
  • Режим debug - в карту инжектится отладочный модуль, позволяющий выводить сообщения об ошибках в отдельный фрейм.
-Игнор-лист позволяющий указать список файлов которые не будут включены в архив карты при сборке

Запланированные макросы

  • --#INLINE для маркировки функций подлежащих инлайну в пределах текущего файла
  • --#INLINE GLOBAL для маркировки функций и переменных подлежащих инлайну во всех файлах
  • --#IF для начала блока условной компиляции, предварительно без серьезных вычислений, только на основе сравнения констант
  • --#ELSE для начала блока else при условной компиляции
  • --#END для завершения блоков у любых блочных макросов

Реализованные макросы

  • RAW('A000') для конвертации равкодов в число при компиляции.
  • --#INLINE для маркировки переменных подлежащих инлайну в пределах текущего файла. Локальные переменные инлайнятся с удалением объявления/присвоения переменной из кода, а для глобальных объявление/присвоение переменной сохраняется.
  • --#ALIAS для назначения метки файлу. Взаимозаменяем с макросом #NAME.
  • --#AFTER для указания списка меток, которые должны быть включены в код карты прежде чем можно будет включить туда текущий файл. При отсутствии этого макроса файлы включаются в порядке обхода папок и только после кода сгенерированного WE.

На рассмотрении

  • Управление порядком включения файлов кода в итоговый код карты через макрос --#IMPORT вставляющий код из указанного файла в место расположения макроса. При такой реализации импортированный файл включается в код как есть, столько раз, сколько использован макрос, защита от конфликтов имен полностью на совести разработчика.
  • Управление порядком включения файлов кода в итоговый код карты через макрос --#REQUIRE вставляющий код из указанного файла в место расположения макроса. При такой реализации импортированный файл включается в код путем оборачивания в функцию и возврата объекта из этой функции. Также возможно наличие проверки, позволяющей избежать повторного включения одного и того же модуля. В целом, предполагается что этот макрос будет работать аналогично стандартному require, за исключением невозможности динамически формировать пути к включаемым файлам.
  • Фреймворк, который будет поставляться вместе с плагином и который можно будет подключить для получения каких-то дополнительных возможностей в рантайме. Например, система модулей или библиотек, каст-система, различные универсальные утилиты и так далее.
  • Расширенная отладочная система, позволяющая по клику в отладочном фрейме внутри игры получить переход на место в коде, в котором возникла показанная в отладочном фрейме ошибка, если это место возможно обнаружить. Причем переход не к финальному монолитному коду карты, а конкретно в тот файл, из которого эта строка попала в итоговый код. Возможно будет работать в два этапа для упрощения реализации, сперва клик в отладочном фрейме экспортирует данные об ошибке в файл, а потом клик в VSCode читает информацию из файла и выполняет переход.
  • Режим сборки карты, при котором код из внешних файлов переносится в триггеры в таком виде чтобы его мог исправно сохранять редактор. Предназначен для выкладывания карты на сайт, чтобы люди без настроенной среды разработки тоже могли воспользоваться. Поскольку редактор не сможет обработать макросы - их необходимо обработать до импорта в триггеры.
  • Встроенный slk-оптимизатор, конвертирующий данные РО в slk таблицы при запаковке карты.
  • Подсказки и автокомплит для макросов.
  • Доступ к данным карты из среды разработки, в частности подсказки и автокомплит для равкодов.
  • Поддержка линукса, а также других IDE кроме VSCode. Несомненно нужно, но очень затратно по времени.

Разработка

Стартовое состояние

Имеется плагин warcraft-vscode, выполняющий большую часть функций интеграции и билдера. К сожалению, автором этого плагина было принято несколько сомнительных решений, в частности код оборачивается в громоздкую систему имитирующую работу require и это поведение невозможно отключить. Требует серьезной доработки. В составе содержит кастомный сборщик карты, умеющий собрать mpq архив по списку файлов в конфиге.
Для подсветки синтаксиса и поиска синтаксических ошибок используется плагин sumneko.lua, включащий в себя языковой сервер Lua, обработку аннотаций EmmyLua и другие полезные фичи. Не содержит из коробки списка нативок, поэтому их приходится подавать ему из внешних файлов. Мог бы работать лучше, но самостоятельная доработка того не стоит, тем более плагин находится в активной разработке автором и постепенно становится только лучше.

Первая итерация

  • Скачаны исходники warcraft-vscode, проведена настройка окружения для компиляции
  • Безжалостно удалены лишние фичи из кода плагина, такие как обработка кода шаблонами, имитация require и нерабочие макросы условной компиляции, загрузка библиотек с гитхаба и так далее
  • В тестовых целях временно добавлена обработка простых и рабочих макросов условной компиляции
  • Начат процесс приведения плагина к виду, в котором его можно было бы опубликовать не опасаясь проблем с авторским правом, фактически он переписывается с нуля с минимальным использованием оригинального кода

Вторая итерация

  • Начата разработка внешнего компилятора
  • Реализован парсинг кода из файла путем токенизации
  • Реализованы макросы #INLINE и RAW
  • Реализован вывод кода в файл путем обратной конвертации токенов
  • На текущем этапе обрабатывается только один файл - нет ни поиска других внешних файлов ни указания пути по которому должны сохраняться результирующие файлы

Третья итерация

  • В этой итерации планируется допилить компилятор до состояния когда он будет способен самостоятельно найти все внешние файлы с кодом по указанному пути, скомпилировать их и вывести результирующий файл в указанное место. (DONE)
  • Поскольку способ подключения внешних файлов пока под вопросом - принятие этого решения тоже входит в эту итерацию. (DONE, для начала реализованы макросы #NAME/#ALIAS и #AFTER, сойдет пока)
  • Также на эту итерацию запланирована интеграция компилятора с плагином к VSCode, чтобы в плагине остались только функции билдера и интеграции, а вся компиляция выполнялась внешним компилятором.(DONE, в предварительной версии)

Четвертая итерация

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

FAQ

Q: Зачем козе баян? Что не так с Lua без дополнительного компилятора?
A: Прежде всего, ради поддержки импорта кода из внешних файлов и возможности работать с кодом карты вне редактора.
Q: Поддержка JASS?
A: Нет и не планируется. Но вместе с релизом будут выложены исходники - все желающие смогут попробовать самостоятельно адаптировать тулсет под JASS.
Q: Когда релиз? Где скачать?
A: Как только так сразу. Скачать можно будет сразу после релиза, из маркетплейса плагинов к VSCode или с XGM.

Вместо послесловия

Разработка ведется по мере наличия свободного времени, с периодической фиксацией результатов.
Когда плагин и компилятор будут пригодны к использованию - они появятся в маркетплейсе VSCode и здесь.
Идеи и предложения приветствуются.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
29
5 лет назад
0
Т.е. это еще и парсер нужен который будет парсить wct и wtg на предмет изменений...
Код передаётся через гитхаб и посему парсить ничего не нужно. Но над картой ещё работают люди, которым код какраз не нужен, а нужно чтоб просто карта работала.
0
24
5 лет назад
0
NazarPunk, если код передается через гитхаб - значит у всех кто работает с кодом настроена среда разработки. Зачем тогда полностью синхронизировать код с редактором пофайлово, если его можно весь в один блок кастом-скрипта вынести и не париться, а в редакторе триггеров оставить отдельными вкладками только всякие настройки, которые только через редактор и будут редактироваться?
5
24
5 лет назад
5
Завершена третья итерация.
По состоянию на сейчас имеется
  • рабочий компилятор с базовым функционалом
  • честно сворованный из warcraft-vscode упаковщик карты
  • запиленый на основе warcraft-vscode плагин к VSCode, вызывающий компилятор и упаковщик, а также запускающий игру и редактор
План на ближайшее будущее - предварительный релиз с ручной установкой и подготовка к релизу полноценному, через маркетплейс плагинов к вскоду.

В связи с тем что редактор показал возможность подхватывать abilitydata.slk из карты-папки, в список запланированных на ближайшее время фич добавляется игнор-лист для упаковщика карты, чтобы можно было указать ему "это файлы только для редактора, не надо совать их в запакованую карту". А в запланированные на будущее фичи - инжект плагином пофикшеного abilitydata.slk в карту для отображения скрытых способностей.
0
29
5 лет назад
0
prog, лей сразу в маркетплейс как бета версию, так удобнее для всех, сами так и делали. До сих пор так и не выпустили 1.0 версию :D marketplace.visualstudio.com/items?itemName=ardenivanov.svelte-i...
Автокомплит планируется? Например я начинаю писать равкод, а он мне достает инфу из карты, и пишет, что этот равкод принадлежит тому то и т.д.?
Автокомплит по API будет?
0
24
5 лет назад
Отредактирован prog
0
alexprey, пока в коде плагина слишком много остатков от стороннего плагина warcraft-vscode чтобы лить в маркетплейс, поэтому первая бета будет все-же на ручной установке, когда до этого дойдет дело, а потом таки сяду причешу код и начну разбираться с маркетплейсом.
Автокомплит по API вара - через сторонний плагин sumneko-lua, это и ланг сервер и эмми-луа аннотации и другие полезные фичи. Для него в комплекте будут идти конфиги и дефинишны API, чтобы достаточно было поставить и можно было пользоваться, но сам sumneko-lua используется оригинальный.
Автокомплит по API компилятора - мне очень хотелось бы, но я понятия не имею как он будет работать параллельно с ланг-сервером, да и не факт что я найду время его запилить - все-же запил плагинов к вскоду это немного далековато от моего базового набора скилов.
Автокомплит по равкодам - интересная мысль, можно попробовать, но те-же проблемы, что и в предыдущем пункте.
2
29
5 лет назад
2
prog, там достаточно все просто происходит, если несколько языковых серверов возвращают информацию на один и тот же контекст, то vscode это просто совмещает вместе. В целом работает там все очень просто. Не обязательно писать автокомплит через языковой сервер, можно внутри плагина просто подписаться на событие и обрабатывать его синхронно. Языковой сервер - это так, для асинхронной обработки и более удобной работы при интегрировании в другие редакторы. При этом код из синхронного в асинхронный переделывается методом копипасты :)
Самая сложная задача в автокомплите - это определение контекста где находится курсор, плюс внешнее окружение. Но тут на помощь приходят стейт машины, если интересно можешь посмотреть исходники нашего плагина и поспрашивать. Могу рассказать как там все работает
2
24
5 лет назад
2
alexprey, ок, значит буду пробовать запилить, после того как с базовым функционалом закончу.
0
28
5 лет назад
Отредактирован PT153
0
--#INLINE для маркировки функций подлежащих инлайну в пределах текущего файла
--#INLINE GLOBAL для маркировки функций и переменных подлежащих инлайну во всех файлах
--#IF для начала блока условной компиляции, предварительно без серьезных вычислений, только на основе сравнения констант
--#ELSE для начала блока else при условной компиляции
--#END для завершения блоков у любых блочных макросов
Что-то похожее я и хотел иметь, но с другим синтаксисом.
<name> - идентификатор.
<expression> - значение или выражение.

регулярное выражение
описание
примеры

 *-- *const +<name> *= *<expression>
Заменяет все вхождения <name> на <expression> во всех файлах. <expression> может являться <name> другой const. Другая константа может быть определена ниже, главное, чтобы не было рекурсий.
-- const INVUL = raw(Ainv)
-- const UserPlayers = 10
-- const AIPlayers = 2
-- const AllPlayers = UserPlayers + AIPlayers

 *-- *localconst +<name> *= *<expression>
Заменяет все вхождения <name> на <expression> в файле, где определена localconst. <expression> может являться <name> другой const или localconst. Другая константа может быть определена ниже, главное, чтобы не было рекурсий.
-- localconst invul_here = INVUL

 *-- *bool +<name> *= *<expression>
 *-- *localbool +<name> *= *<expression>
Тоже самое, что и const, но значения могут быть только true, false, другая bool или даже выражение из операнд bool и localbool и операторов or, and и not. <expression> для bool не может содержать операнды типа localbool.
-- bool debug = true
-- localbool debug_here = debug
-- localbool no_debug_here = not debug_here

 *-- *#if +<expression>( +then)?
 *-- *#elseif +<expression>( +then)?
 *-- *#else
 *-- *#endif
Условная компиляция. <expression> состоит из операнд bool и localbool и операторов or, and и not. #endif можно заменить на #fi или #end.
Для укорочения можно изменить вид операнд и операторов.
false -> 0
true -> 1
and -> *
or -> +
not -> -

 *<bool or localbool var> +<some lua expression>
Условная компиляция в линию. Для этого я и ввёл отдельно тип bool.
debug print(GetUnitName(u))

(RAW|raw)\( *('<rawcode>'|"<rawcode>"|<rawcode>) *\)
конвертирует равкод в число. Может принимать как в кавычках, так и без. С кавычками следует быть аккуратнее, так как сами кавычки могут быть частью равкода.
Так же я бы хотел опцию по удалению лишних пробелов для уменьшения веса кода ПЕРЕД вызовом syntax check.

Ещё бы я хотел, чтобы выражения в константах считались препроцессором.
0
24
5 лет назад
Отредактирован prog
0
PT153, напоминаю, что этот компилятор рассчитан на работу с кодом в VSCode, а WE остается только GUI и все что с кодом не связано. Поэтому, например, не имеет смысла что-то чудить с пробелами перед синтакс чеком т.к. синтакс чек из WE просто не будет вызываться в 99% случаев.

Что касается синтаксиса макросов - я не случайно пошел путем аннотаций к переменным вместо кода в комментах - в моем варианте с этим более-менее прилично работает обычный синтакс-чекер для Lua и мне не нужно писать кастомный.
За счет этого, например, наведя мышку на константу я могу увидеть её значение.
А в результирующем коде от скрина выше останется только print("CONST_VAL")

Аналогично с макросом RAW - он принимает только значения в одинарных кавычках и имена констант чтобы проходить стандартный синтакс-чек. Более того, используется еще и объявление глобальной переменной RAW=FourCC, чтобы если что-то пошло не так с макросом, был шанс на срабатывание стандартного конвертера, ну и строгий синтакс-чек без этого не пройти.
Загруженные файлы
0
28
5 лет назад
Отредактирован PT153
0
Поэтому, например, не имеет смысла что-то чудить с пробелами перед синтакс чеком т.к. синтакс чек из WE просто не будет вызываться в 99% случаев.
Я про syntax check в самом VSCode. Я сказал "ПЕРЕД" для того, чтобы в алгоритме по удалению пробелов можно было засечь ошибку, да и всяко лучше запускать чекер после всех препроцессорных махинаций.
Что касается синтаксиса макросов - я не случайно пошел путем аннотаций к переменным вместо кода в комментах - в моем варианте с этим более-менее прилично работает обычный синтакс-чекер для Lua и мне не нужно писать кастомный.
В целом, так тоже неплохо.
PT153:
Ещё бы я хотел, чтобы выражения в константах считались препроцессором.
На самом деле было бы хорошо делать вычисления для всех выражений без переменных, как это делает python.
Аналогично с макросом RAW - он принимает только значения в одинарных кавычках и имена констант чтобы проходить стандартный синтакс-чек. Более того, используется еще и объявление глобальной переменной RAW=FourCC, чтобы если что-то пошло не так с макросом, был шанс на срабатывание стандартного конвертера, ну и строгий синтакс-чек без этого не пройти.
Мудро.
0
24
5 лет назад
0
Я про syntax check в самом VSCode. Я сказал "ПЕРЕД" для того, чтобы в алгоритме по удалению пробелов можно было засечь ошибку, да и всяко лучше запускать чекер после всех препроцессорных махинаций.
У меня немного другая идеология, которая заключается в том, что валидный код до препроцессора всегда должен выдавать валидный код после препроцессора и наоборот, не валидный код до препроцессора может выдать только не валидный код после препроцессора. Это немного сужает допустимый функционал препроцессора, но избавляет от огромного количества головной боли и хорошо интегрируется с существующими инструментами для работы с Lua.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.