Паттерн State и красивый API парсера исходников

9 ноября 2011 г.

Как-то раз появилась у нас задача — порезать все комментарии в обширном продуктовом коде нашей компании. Ну как порезать — всё порезать, а явадоки оставить. Ну как оставить — если в них есть зашифрованный псевдоним нашего сотрудника (легко узнаваемая последовательность символов), его удалить, а остальное оставить.

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

Задача эта не из самых интересных, потому первую попытку было решено сделать «влоб» — посимвольно считывать файл, явно перехватывая последовательности символов “//” и “/*” и сохраняя в какие-то списки значения комментариев.

Код вроде работал, но был ужасно некрасив, разбить 280-строковые методы на меньшее ну никак не получалось. Мешала жесткая привязка к проверки последовательности символов “//”, “/*”, символам начал строки (если в строке встречается /* или //, то это часть строки, а не комментарий). Со временем у нас завелись баги и перспектива прослеживать как там что присваивается в огромном куске кода никого не радовала…

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

Но зацените какой прекрасный api получился!

Можно просто и легко добавить описание комментариев:
FileReaderContext context = new FileReaderContext();
context.addState(new SpecialBlockState("MULTILINE_COMMENT", "/*", "*/"));
context.addState(new SpecialBlockState("SINGLE_LINE_COMMENT", "//", "\n"));

А можно также просто добавить описание эскейп-символов:
context.addState(new StringState("STRING_SINGLE_QUOTE", '\''));
context.addState(new StringState("STRING_DOUBLE_QUOTE", '"'));

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

А сам результат парсинга представляется в виде списка объектов класса FilePart, вот его интерфейс:
public class FilePart
{
public String getContent();
public String getFilePartType();
}

Архив с кодом можно скачать тут: webfile.ru/5611247

Теги: рубрика Интернет