Comments 7
Реализовать парсинг языка разметки в обычный текст и добавить маппинг индексов из естественного текста в исходный текст.
А зачем парсить именно в текст, а не в дерево разбора? Последнее кажется более логичным вариантом, ведь в нем можно помечать какие элементы нужно проверять, какие — нет (ссылки, цитаты), а какие — проверять по особому (исходный код). В перспективе такое дерево можно использовать и для других функций (например, линтер или перевод). Я рассмотрел такой метод, особенно если Grazie позиционируется под IT.
Но реализация парсера для LaTeX оказалась сложнее, потому что LaTeX не имеет контекстно-свободной грамматики.
Может LaTeX и сложнее, но полноценной контекстно-свободной грамматики под Markdown я тоже не встречал. Как-то даже сам пытался ее написать, но ничего не вышло. В нем много моментов, где требуется дополнительный код для проверки переносов, пробелов и других штук (семантических предикатов).
Как я уже написала, Tree-sitter генерирует парсер на C. Для использования в JavaScript у него есть биндер, который генерирует .wasm файл, и его уже можно запускать в браузере.
Даже странно, что нет биндера в нативный JavaScript. Я конечно толком не изучал эту тему, но этот биндер разве нельзя заюзать node-tree-sitter? nodejs вроде можно адаптировать в браузерный формат.
Я выбрала последний вариант и переписала грамматику из .js в .g4 для ANTLR4. Он генерирует лексер, парсер и визитер на JS, а с помощью antlr4ts можно это всё сгенерировать на TypeScript. Проблема была в том, что одна страница латеха обрабатывалась около 700 мс, а после упрощения грамматики получилось ускорить всего в 2 раза. С такой скоростью обработки страница сайта зависала после каждого введенного символа.
А можно взглянуть на грамматику и сам парсер? Возможно смогу помочь соптимизировать, т.к. 700 мс — это очень много.
В итоге было принято решение отказаться от написания парсера и построения AST. Вместо этого было бы достаточно удалять синтаксические конструкции с помощью регулярных выражений и таким образом получать естественный текст.
А заюзать ANTLR лексер без парсера нельзя было? Он как правило намного легче и быстрее парсера. Все-таки регулярные выражения — это крайний и не лучший вариант.
Добрый день! Простите за долгий ответ, сессия... стажировка....
А зачем парсить именно в текст, а не в дерево разбора?
Парсится в AST само собой и, как Вы хорошо подметили, "в нем можно помечать какие элементы нужно проверять, какие — нет". Так делалось, например, в маркдауне. Там использовалась библиотека от unified с набором методов, в которых можно указать какие вершины при разборе не надо рассматривать. И уже из AST после выкидывания ненужных вершин получался естественный текст, который перенаправлялся в существующий функционал для проверки.
Я конечно толком не изучал эту тему, но этот биндер разве нельзя заюзать node-tree-sitter?
В проекте нет node.js и его не хотели добавлять.
А можно взглянуть на грамматику и сам парсер?
Не могу ответить на такой вопрос, тк уже не в проекте :(
700 мс — это очень много.
Там уже не 700, а 5мс :) 700мс было как раз при самой первой реализации с ANTLR.
А заюзать ANTLR лексер без парсера нельзя было?
Была такая мысль, да. Но я решила сделать свой парсер и у него была такая хорошая производительность относительно ANTLR, что оставили его. Интересный вопрос: а насколько быстрее лексер ANTLR без парсера чем с ним? У меня не получилось с ходу найти какие-либо метрики.
В проекте нет node.js и его не хотели добавлять.
А эта версия в браузере разве не может запускаться (помимо node.js)?
Там уже не 700, а 5мс :) 700мс было как раз при самой первой реализации с ANTLR.
Ну так написано, что после упрощения грамматике удалось ускорить в два раза, т.е. в 350мс, а это все равно долго. И из-за этого вы перешли на регулярки как понял.
Интересный вопрос: а насколько быстрее лексер ANTLR без парсера чем с ним?
Существенно быстрее, т.е. лексер — это, можно сказать, регулярка, которые покрывает весь текст, а не часть (хотя ANTLR лексер на самом деле может быть контекстно-свободным, но это не суть). И работает даже лучше обычных регулярок, т.к. при захвате символов учитываются все токены, а не один. В результате его работы получается линейная структура из токенов. А парсер возвращает древовидное представление, в нем могут быть возвраты, скорость работы медленней.
А эта версия в браузере разве не может запускаться (помимо node.js)?
Запуск в браузере требовал дополнительного разрешения на запуск файлов. Это увеличивает время проверки каждой версии плагина в Гугле :(
Ну так написано, что после упрощения грамматике удалось ускорить в два раза, т.е. в 350мс, а это все равно долго. И из-за этого вы перешли на регулярки как понял.
Да, так и было.
Существенно быстрее, т.е. лексер — это, можно сказать, регулярка, которые покрывает весь текст, а не часть (хотя ANTLR лексер на самом деле может быть контекстно-свободным, но это не суть). И работает даже лучше обычных регулярок, т.к. при захвате символов учитываются все токены, а не один. В результате его работы получается линейная структура из токенов. А парсер возвращает древовидное представление, в нем могут быть возвраты, скорость работы медленней.
Звучит круто, спасибо за ответ! Жаль не успели попробовать и проверить на практике.
Полноценный парсер теха — это большая головная боль, особенно когда его потом надо во что-то сконвертировать. Единственный проект, который более или менее с этим справляется — это https://dlmf.nist.gov/LaTeXML/. Там компилятор теха в XML, из которого потом можно сделать человека (после доработки напильником).
А точно ли васм это проблема? Писали расширение с ядром на раст и все изменения рассматривают не больше, чем за сутки
Парсинг Markdown и LaTeX в Grazie Chrome Plugin