BPattern: переписать движок в стиле Smalltalk

BPattern: переписать движок в стиле Smalltalk


Движок перезаписи — это совершенно гениальное изобретение Джона Бранта и Дона Робертса, которое было представлено вместе с рефакторингом браузеров (см.) «Инструмент рефакторинга для Smalltalk», 1997 г.). Это дает нам удивительные возможности сопоставления и перезаписи на уровне AST.

Но давайте будем честными: сколько людей на самом деле помнят его синтаксис?

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

Есть ли такое?

``@receiver isNil ifTrue: ``@nilBlock -> ``@receiver ifNil: ``@nilBlock

Или, может быть, с одинарными обратными кавычками?

`@receiver isNil ifTrue: `@nilBlock -> `@receiver ifNil: `@nilBlock

Фактически, Оба Версии работают, но к целевому узлу применяются разные фильтры. Постарайтесь вспомнить, какой именно.

И это только начало.

Знаете ли вы, что вы можете использовать подстановочный знак части селекторов?

`@receiver `anyKeywordPart: `@arg1 staticPart: `@arg2

Вы можете переименовать ключевые слова, используя:

`@receiver newKeywordPart: `@arg1 staticPart: `@arg2

Или даже поменять их местами:

`@receiver staticPart: `@arg2 `anyKeywordPart: `@arg1

Это невероятно мощно. Но как все это запомнить?

Как и в случае с обычным кодом Smalltalk, я исследую систему, используя диспетчеров, разработчиков и инспекторов, постепенно восстанавливая свое понимание. Здесь он ломается. Соответствующий синтаксис находится внутри строк и невидим для стандартных инструментов навигации. Код не завершен. Никакого рефакторинга. Никакой помощи со стороны окружения.

Так как же мы можем получить электричество без синтаксического налога?

это прямо здесь бшаблон Войдите:

[ any isNil ifTrue: anyBlock ] bpattern

бшаблон

бшаблон Предоставьте свободный, собственный для Smalltalk API поверх Rewrite Engine, используя простой блок Smalltalk Как образец.

Вы создаете экземпляр BPattern, отправляя #bpattern Сообщение блоку. Переменные и селекторы внутри блока определяют шаблоны, которые будут сопоставляться с целевыми узлами AST. Все начинается с традиций Любой Слово действует как подстановочный знак. Все остальное должно структурно совпадать.

Под капотом BPattern создает шаблон AST, используя те же классы узлов шаблона, что и механизм перезаписи. Все исходные механизмы сопоставления и перезаписи по-прежнему здесь – просто заключены в более доступный интерфейс со сценариями.

Вы можете подумать о BPatterns Smalltalk DSL Для перезаписи движка.

Pharo уже предоставляет специальные инструменты для переписывания движков, например StRewriterMatchToolPresenter:

BPattern: переписать движок в стиле Smalltalk


При использовании BPattern ничего из этого не требуется. Паттерн — это всего лишь один блок. Добавьте еще одно сообщение, и Simple DoIt выполнит всю работу.

Чтобы найти все соответствующие методы:

[ anyRcv isNil ifTrue: anyBlock ] bpattern browseUsers


Чтобы переписать их:

[[ anyRcv isNil ifTrue: anyBlock ] ->  [ anyRcv ifNil: anyBlock ]] brewrite preview

четко уточняя рисунок

Очевидно, вы можете сузить шаблон, используя #with: message: :

[ anyVar isNil ifTrue: anyBlock ] bpattern with: [ anyVar ] -> [:pattern | pattern beVariable ]

бПоскольку это обычный код Smalltalk, все стандартные инструменты разработки работают «из коробки»: подсветка синтаксиса, автодополнение кода, навигация и рефакторинг:

Просмотрите разработчиков #bechangeable Сообщение и другие фильтры вы найдете ниже BPatternVariableNode класс, типа #beInstVar Или #beLocalVar. Если ты что-то помнишь, Просто добавьте метод. Новый синтаксис не требуется.

Вы также можете использовать произвольный блок в качестве фильтра:

[ anyVar isNil ifTrue: anyBlock ] bpattern 

         with: [ anyVar ] -> [:pattern | 

                           pattern beInstVar where: [:var | var name beginsWith: 'somePrefix' ]]

блок фокусировки [anyVar] Переменные, используемые для ссылки на то, где должен применяться блок конфигурации. Это позволяет избежать необработанных строк для имен переменных и делает эти конфигурации удобными для инструментов разработки:

Еще раз о шаблонах сообщений

Давайте теперь вернемся к примерам подстановочных знаков селектора с нуля, используя BPattern.

Переименование ключевого слова:

[

         anyRcv anyKeywordPart: anyArg1 staticPart: anyArg2 ] 

                  -> [ anyRcv newKeywordPart: anyArg1 staticPart: anyArg2 ]

] brewrite.

Замена ключевых слов:

[

         anyRcv anyKeywordPart: anyArg1 staticPart: anyArg2 ] 

                  -> [ anyRcv staticPart: anyArg2 anyKeywordPart: anyArg1 ]

] brewrite.

Шаблоны сообщений также можно уточнить с помощью #с: Сообщение:

[ any anyMessage: any2 ] bpattern 

with: #anyMessage: -> [:pattern | pattern beBinary ];

browseUsers.

Это находит все методы с двоичными сообщениями:


Добавьте еще один фильтр, чтобы между литералами оставались только двоичные файлы:

[ any anyMessage: any2 ] bpattern 

with: #anyMessage: -> [:pattern | pattern beBinary ];

with: [ any. any2 ] -> [ :pattern | pattern beLiteral ]; 

browseUsers


Старый синтаксис также поддерживает буквальные шаблоны, но удачи вам в поиске примера.

Шаблоны сообщений также можно настроить с произвольными условиями:

[ any anyMessage ] bpattern 

with: #anyMessage -> [:pattern | pattern where: [:node | node selector beginsWith: 'prim' ]];

browseUsers


статус и что дальше

B-образцы не отображаются Каждый Механизм перезаписи еще не представлен, но некоторые из них уже поддерживаются, включая полный шаблон метода. #bmethod.

Полную информацию смотрите в репозитории GitHub:

И ознакомьтесь со следующей публикацией в блоге об упрощенном API устаревания, построенном на основе BPattern:

Leave a Reply

Your email address will not be published. Required fields are marked *