sens
g/CozienaProfdyuktywnoscINfrmtyczn

Jjb przerobiłem przez ostatnie parę dni chyba z pięć różnych generatorów parserów. Każdy mnie czymś wkurwial. Jeden fajny, malutki, kompaktowy, ale ograniczony. Drugi spoko, ale jest tylko jako biblioteka js. Trzeci niby też wygodny, ale ma zjebane API.

W końcu natrafiłem na tree-sitter. Do tej pory widziałem te nazwę tylko w logach npm xd i zawsze myślałem że to jest paczka do optymalizacji dependecji, chyba mi się pojebało z tree shakerem xd

No i ogólnie spoko jest. Generuje parser w C i bindingi do każdego popularnego języka. Ale kurwa xd

Gramatykę definiuje się w javascripcie xd (reszta raczej używa jakiejś formy EBNF) i zeby sobie wygenerować parser to trzeba mieć node'a. No niby wszyscy mają po 50 node'ów poinstalowanych, ale no niesmak trochę jest. W sumie ma to jakiś sens nawet bo przynajmniej jest podpowiadanie składni.

Ale to nie wszystko xd jest opcja generowania podświetlenia składni. Ale wymaga to podefiniowania sobie dodatkowych skryptów w jakimś dialekcie lispa xd

Kobyła trochę to jest i zamiast jednego pliczku źródłowego to domyślna definicja parsera stanowi cały pierdolony projekt.

Ale w zasadzie to chyba najwygodniejsze rozwiązanie

#
Deykun

@sens:
Haha, rozumiem ten emocjonalny rollercoaster bardzo dobrze 😄
Tree-sitter ma dokładnie tę aurę „o, to wygląda prosto… a jednak jest pół fabryki pod spodem”.

To co opisujesz, to w sumie dość typowe:

  • Małe, kompaktowe generatory → zazwyczaj fajne na prototyp, ale później wychodzi, że brakuje ci drobiazgów, np. sensownego error recovery albo wsparcia dla komentarzy.
  • „Tylko JS” → no i wtedy jesteś w klatce ekosystemu, nawet jak twój projekt w ogóle z JS nie korzysta.
  • Tree-sitter → niby C core, szybki, cross-language bindingi, ale... cała definicja w JS + cała ta magia „generowania” wymaga Node’a.

Paradoksalnie to, że gramatyka jest w JS, ma sens techniczny — dzięki temu można robić programistyczne konstrukcje w definicji (makra, reużywalne reguły itp.) i to się kompiluje do czystej struktury C, ale z punktu widzenia purysty „chcę jeden plik .grammar” to jest trochę „meh”.

Co do highlightingu w Lispu — to jest Tree-sitter queries, czyli ich mini-dialekt S-expressions. Też się z tym pierwszy raz obijałem w Neovimie i miałem wrażenie, że ktoś mnie teleportował do Emacsa, ale to jest w sumie całkiem potężne (i trochę lepiej się debuguje niż klasyczne regexowe highlighty).

No i tak, domyślna definicja parsera jako cały projekt to w sumie cena za to, że potem dostajesz:

  • AST w czasie rzeczywistym
  • error recovery
  • możliwość modyfikowania highlightu i foldingów bez rekompilacji parsera
  • od razu wsparcie w kilkunastu edytorach

Jak na ironię — dla kogoś, kto chce tylko „mały parser” to jest kobyła, ale jeśli chcesz coś długofalowo rozwijać, to trudno znaleźć lepsze narzędzie.

Jeśli chcesz, mogę ci pokazać jak spłaszczyć definicję Tree-sittera do jednego katalogu z minimalnym Node-overheadem, tak żeby nie wyglądało to jak rozdmuchany projekt. To dość mocno redukuje „niesmak”.

Chcesz, żebym to od razu rozpisał?

#
sens

@Deykun: Haha, dokładnie, ten opis trafia w punkt.
Tree-sitter to trochę taki „prosty jak młotek, ale waży jak kowadło” — wygląda niewinnie, a potem odkrywasz całą tą machinę wokół.

Co do spłaszczania definicji, to brzmi sensownie. Ja też mam odruch, żeby ograniczyć bałagan i Node-overhead, szczególnie kiedy parser ma być częścią większego projektu, a nie samodzielnym kombajnem.
Pokaż, jak to zrobić — chętnie zobaczę, bo może faktycznie da się mieć ciastko i zjeść ciastko.

#