Nowości w języku

Ten dokument opisuje zmiany w języku w stosunku do JOSKIPI. Są to zarówno zmiany typowo składniowe, jak i nowa funkcjonalność.

Główne zmiany składniowe

1. Operator flex zmienia nazwę na class. Motywacja: skrót flex nie kojarzy się z klasą gramatyczną, poza tym obsługujemy dowolny tagset, więc klasy słów nie muszą być klasami fleksyjnymi.
2. Zbiory stringów zapisujemy w nawiasach kwadratowych (np. ["zawsze", "nigdy", "czasami"], []), zbiory symboli z tagsetu zapisujemy w nawiasach wąsowych ({nom,acc}, {cas}, {}). Pozostawiliśmy cukier składniowy dla zbiorów jednoelementowych (można pominąć nawiasy — sg = {sg}, "tak" = ["tak"]). Motywacja: teraz typ pustych zbiorów jest jednoznaczny.
3. Dowolne wyrażenie można do woli otaczać nawiasami.
4. Dodaliśmy komentarze blokowe — składnia /* … */ (bez zagnieżdżania). Działają też komentarze jednoliniowe //.
5. Wszelkie stringi można zapisać zarówno w cudzysłowach ASCII, jak i w apostrofach ASCII (jak w Pythonie, np. '"' oznacza znak cudzysłowia). Oprócz tego dopuszczalne są sekwencje kontrolne (escape sequences) zdefiniowane przez ICU, m.in. \uhhhh (znak unikodowy o podanym kodzie).
6. Operatory uzgodnienia: usunęliśmy ostatni, nadmiarowy argument, czyli liczbę atrybutów („bitów”). Reszta argumentów pozostaje na swoich miejscach, semantyka niezmieniona.
7. Mamy literały True, False, {} (pusty zbiór symboli), [] (pusty zbiór stringów).
8. Nazwy symboli z tagsetu można otoczyć znakami Gravis („backtick”, U+0060 GRAVE ACCENT). To może być przydatne, gdyby w którymś tagsecie symbol pokrywał się ze słowem kluczowym języka, np. gdybyśmy mieli symbol if, można go zapisać `if` i parser nie potraktuje tego jak słowa kluczowego.
9. Nazwy zmiennych również można otoczyć znakami Gravis, np. $`agr` to zmienna o nazwie agr. To tylko możliwość, nie zachęcamy do nadużywania jej.

Ujednolicona składnia pliku WCCL i leksykony

Język JOSKIPI definiował różne składnie w zależności od konkretnych zastosowań: plik definiujący wzorce tagera miał inną składnię, inną składnię miały reguły tagowania, a jeszcze inną plik zawierający jeden predykat. W WCCL-u definiujemy ogólną składnię pliku WCCL. Pozwala ona na używanie pliku o tej samej strukturze w większości zastosowań. Pozwala to też na odwołanie się do zewnętrznych słowników (leksykonów), które są ładowane jednorazowo, po czym mogą z nich korzystać wszystkie wyrażenia zawarte w pliku.

Leksykony ładowane są za pomocą deklaracji import umieszczonej na początku pliku. Odwołanie do leksykonu realizowane jest poprzez operator lex(STRSET, LEXNAME), gdzie STRSET to dowolne wyrażenie zwracające zbiór napisów, natomiast LEXNAME to pojedynczy napis będący nazwą leksykonu (zgodnie z deklaracją import). Operator zwraca zbiór napisów — każdy napis należący do leksykonu zamieniany jest na przypisaną mu wartość, natomiast napisy pozostałe są pomijane.

Składnię oraz format pliku z leksykonem opisano szczegółowo tu.

Zdania z anotacją (chunks/named entities)

Operator isannpart(pos, phrase) wymaga zdania oznakowanego anotacjami (AnnotatedSentence). Zwraca True, jeśli przez podaną pozycję przechodzi anotacja (dowolnej długości) w kanale o nazwie phrase.

Operator isannhead(pos, phrase) działa w sposób analogiczny, lecz zwraca True, jeśli dodatkowo w danej pozycji znajduje się nadrzędnik frazy phrase.

Operatory isannbeg(pos, phrase) i isannend(pos, phrase) sprawdzają, czy na danej pozycji znajduje się odpowiednio pierwszy lub ostatni token anotacji.

Silne rozróżnienie typów danych

W JOSKIPI typy danych mieszały się ze sobą. W szczególności możliwe było utworzenie zbioru {subst, "kaczka"}. Operatorom działającym z założenia na symbolach można było przekazać stringi i vice-versa.

Teraz mamy silne rozróżnienie typów danych. Każde wyrażenie — stałe, zmienne i operatory z argumentami — ma jasno określony zwracany typ. Dzięki temu więcej błędów można wykryć na etapie parsowania. Konsekwencją była konieczność zmiany wspomnianej składni zbiorów.

Pozycje są pełnoprawnym typem danych

1. Wycofaliśmy składnię $-2V. Przesunięcia realizowane są teraz infiksowymi operatorami + i -. Przykładowo, $V - 2, $3 - 2, begin + 1. Uwaga: operacje te nie są przemienne. Na pierwszym miejscu zawsze musi stać pozycja, na drugiej — liczba całkowita. Nawet jeśli oba te argumenty wyglądają tak samo (2 + 2), to traktowane są różnie. Składnia nie pozwala na zapisy typu 2 + 2 + 2 + 2; jeśli komuś bardzo na tym zależy, można to ująć w nawiasy: ((2 + 2) + 2) + 2 (wynik każdego działania jest typu pozycja).

2. Operator equal oraz operatory warunkowe mają też swoje warianty dla typu pozycja (można tam przekazać zarówno stałą, zmienną, jak i dowolny operator zwracający typ pozycja). Dwie pozycje są sobie równe wtt. gdy:
  • obie mieszczą się w granicach zdania i wskazują na ten sam token,
  • obie są poza granicami zdania i wskazywałyby na ten sam token, gdyby zdanie było odpowiednio długie,
  • obie mają wartość nowhere.

Zmienne czterech typów danych

1. Pozycje: składnia $Var. Jak wspomniano wyżej, nie ma już odwołań do zmiennej z przesunięciem, zamiast tego są operatory + i -.
2. Zbiory stringów: składnia $s:V.
3. Zbiory symboli z tagsetu: składnia $t:V.
4. Wartości logiczne: składnia $b:V.

Uwaga: nazwa zmiennej nie musi się zaczynać z wielkiej litery. Proponuję jednak dalej używać zmiennych zaczynających się z wielkiej litery w ramach konwencji.

Jawne przypisanie wartości zmiennej: operator setvar(TARGET, EXPR), gdzie TARGET to zmienna, a EXPR to wyrażenie zwracające wartość tego typu. Np. setvar($P, begin + 2), setvar($t:Casehere, cas[0]).

Operatory warunkowe

1. Operator if(condition, value_when_true, value_when_false). Operator zdefiniowany jest dla czterech typów: zbiór symboli, zbiór stringów, wartość logiczna, pozycja. Jeśli typ wyrażenia value_when_true będzie inny niż typ value_when_false, parser zgłosi błąd.

2. Operator if(condition, value_when_true). Jeśli warunek jest niespełniony, operator zwraca wartość domyślną dla danego typu, czyli odpowiednio {}, [], False, nowhere. Operator ten jest odpowiednikiem operatora ? value_when_true ? condition, choć semantyka jest zmieniona: tamten operator w przypadku niepowodzenia zwracał pusty zbiór, niezależnie od typu wyrażenia zwracanego w razie sukcesu. W nowym języku mamy silnie określone typy danych, więc obie wartości muszą mieć ten sam typ.

Operatory warunkowe można dowolnie zagnieżdżać. Np.

if(
   rlook(if(inter(class[0], subst),1,0), end, $Adj,
      in(class[$Adj], {adj, pact, ppas})
   ),
   if(inter({m1,m2,m3}, gnd[$Adj]),class[$Adj])
)

Operator regex

regex(strop, re_text) zwraca True, jeśli wszystkie elementy zbioru stringów zwróconego przez operator strop spełniają wyrażenie regularne re_text (zgodne z ICU, można korzystać z character properties). Np. regex(["nie","on"],"\\p{L}+") zwróci True.

Zakresy pozycji

Operatory iterujące (np. rlook, only) oraz uzgodnienia na zakresach (np. agr) przycinają podane zakresy do granic zdania zanim nastąpi ewaluacja właściwego warunku.

Pomijanie tokenów spełniających predykat

Wprowadzamy nowy operator iterujący skip(pos1, posvar, pred, n), którego zadaniem jest ustawienie wartości zmiennej posvar na token oddalony o n od pos1, licząc jedynie tokeny niespełniające predykatu pred. Operator jest przydatny do eksperymentów z pomijaniem tokenów nieistotnych składniowo (np. partykuł).

Nowe operatory pomocnicze

inside(pos) i outside(pos) sprawdzają, czy pozaycja jest odpowienio wewnąytrz lub poza zdaniem.
intersection oraz union pozwalają wykonywac operacje sumy i iloczynu na zbiorach napisów i symboli z tagsetu.
ambiguous dla typów zbiorowych zwraca, czy zbiory te są wieloelementowe; dla typu pozycja zwraca, czy token zawiera więcej niż jeden leksem.
singular(symset) (zdefiniowany tylko dla zbiorów symboli z tagsetu) sprawdza, czy każdy z atrybutów jest reprezentowany w podanym zbiorze przez co najwyżej jedną wartość (np. że zbiór zawiera po jednej wartości przypadka i rodzaju)

Podjęzyk reguł dopasowania

W WCCL-u oprócz reguł tagowania (analogicznych do JOSKIPI) wprowadzono podjęzyk reguł dopasowania. Reguły te nie odwołują się do bieżącej pozycji w zdaniu, lecz iterują każdorazowo po całym zdaniu i znakują rozpoznane anotacje.

Szczegóły opisano w specyfikacji podjęzyka reguł dopasowań.