Przejdź do treści

olski.werdykt.zdanie

Werdykt o jednym zdaniu wraz z wierszami, którymi się go wypisuje.

werdykt jest jedynym miejscem, które ten werdykt składa: z rozbioru, z poprawki (olski/werdykt/odrzucone.py) i z wykazów liczonych z lasu (olski/werdykt/wykazy.py). Tamte dwa moduły o werdykcie nie wiedzą, więc funkcja, która pyta werdykt gotowy, jest tutaj, a nie przy swoim temacie: dalsze_zatrzymania i niespełnione_żądania biorą Verdict argumentem.

FRAGMENT = 'fragment' module-attribute

NIEDOMKNIĘTE = 'unclosed' module-attribute

BRAK_ODCZYTANIA = 'brak odczytania' module-attribute

Verdict dataclass

What olski says about one sentence.

Source code in olski/werdykt/zdanie.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
@dataclass(frozen=True)
class Verdict:
    """What olski says about one sentence."""

    #: Zdanie tak, jak stoi w tekście. Segmenty są krawędziami grafu, a nie
    #: listą, więc sklejone dają naraz każdy podział, jaki Morfeusz na formie
    #: widzi: ``ktoś`` wychodzi wtedy jako ``kto ktoś ś``.
    text: str
    result: Result
    #: Formy nie do ominięcia, którym żadna produkcja nie bierze ani jednego
    #: czytania: odrzucenie stanęło na nich, a nie na strukturze. Pola bez
    #: wartości domyślnej, bo pusta krotka jest tu twierdzeniem o zdaniu, a
    #: ``Nowa program zapisuje ustawienia.`` ma je puste i jest odrzucone.
    nielicencjonowane: tuple[str, ...]
    #: Forma, której nie wzięła ani jedna analiza częściowa, czyli miejsce, na
    #: którym odrzucenie stanęło; ``None``, gdy analiza doszła do ostatniego
    #: znaku zdania. Pola bez wartości domyślnej z tego samego powodu co wyżej:
    #: ``None`` jest tu twierdzeniem, a nie brakiem odpowiedzi.
    #: Twierdzeniem jest tylko wtedy, gdy o zatrzymanie pytano.
    #: Przebieg, który nie pytał (:func:`werdykt`), zostawia tu również ``None``.
    #: Rozdziela te dwa ``Result.furthest`` i o niego pyta :meth:`explain`.
    zatrzymanie: str | None
    #: Poprawka jednego znaku, po której olski ten napis czyta, albo ``None``.
    #: Pole, a nie właściwość, bo :func:`olski.werdykt.odrzucone._naprawa`
    #: kosztuje rozbiór, a właściwość płaciłaby tyle razy, ile razy ktoś ją przeczyta.
    naprawa: Naprawa | None

    @property
    def punktowane(self) -> bool:
        """Czy tekst punktuje ten napis jako zdanie.

        Mianownik pomiaru pyta o to, a nie o :attr:`status`, bo odpowiedź jest ta
        sama nad oboma werdyktami o napisie niepunktowanym i nie kosztuje rozbioru,
        którego kosztuje :attr:`domknięcie`
        (:class:`olski.werdykt.tekst.Podsumowanie`).
        """
        return bool(SENTENCE_CLOSE.search(self.text))

    @property
    def zgłoszenie(self) -> bool:
        """Czy narzędzie ma o tym zdaniu coś do powiedzenia.

        Wydruk domyślny niesie dwa zgłoszenia: wieloznaczność oraz poprawkę
        jednego znaku, a znaleziskiem jest tylko druga
        (docs/subset.md#wieloznaczność-jest-odpowiedzią-a-nie-znaleziskiem).
        Zaimek wskazujący na dwie rzeczy naraz pada obok werdyktu,
        bo rzeczy nazywa zdanie obok (``olski/odniesienia.py``), więc tutaj go nie ma.
        Warunek stoi tu raz, bo pyta o niego wydruk nad każdym zdaniem osobno;
        :class:`olski.werdykt.tekst.Podsumowanie` liczy każde z tych zgłoszeń
        nad tekstem i liczy je osobno.

        Napis niepunktowany zostaje poza zgłoszeniem także wtedy, gdy poprawkę
        ma, bo nagłówek i pozycja listy dochodzą tu jako takie napisy i żadne z
        nich nie jest zdaniem, którego autor nie domknął
        (docs/extraction.md); wydruk pokazuje je do flagi ``--zatrzymania``.
        """
        return self.punktowane and (self.result.ambiguous or self.naprawa is not None)

    @property
    def czytane(self) -> bool:
        """Czy olski to zdanie czyta.

        Nieczytane są trzy: zdanie odrzucone, napis, którego nic nie domyka,
        i fragment. O polszczyźnie żadnego z nich olski nie orzeka,
        więc wydruk milczy o nich do flagi (``olski/check.py``).
        """
        return self.punktowane and not self.result.rejected

    @property
    def status(self) -> str:
        """Klasa, do której werdykt to zdanie liczy, czyli słowo pomiaru.

        Wydruk komendy go nie podaje, bo dzieli zdania po liczbie odczytań,
        a nie po tym, czy narzędzie ma o zdaniu co powiedzieć (:attr:`znalezisko`).
        Czytają je pomiar pokrycia (``olski/pokrycie.py``), sondy w ``harness/``
        i znaczek na stronie (``witryna/skrypt.js``).
        """
        if not self.punktowane:
            return NIEDOMKNIĘTE if self.naprawa else FRAGMENT
        return self.result.status

    @property
    def readings(self) -> list[tuple[dict[str, str], ...]]:
        """Streszczenia odczytań, każde raz (:func:`streszczenia`).

        Odczytanie jest krotką streszczeń, po jednym na zdanie składowe, więc
        wpisem tej listy jest krotka, a nie jedno streszczenie.

        Lista jest po to, żeby pokazać różnicę między odczytaniami,
        a różnicę spoza zasięgu streszczenia nazywa wiersz o konstytuencie
        (:func:`_rozbieżny`), więc powtórzony napis nie zostawia jej nienazwanej.
        Liczbę odczytań podaje las (:attr:`Result.ile`),
        więc skrócenie tej listy jej nie rusza.
        """
        return [
            tuple(map(_po_szkolnemu, streszczenie))
            for streszczenie in streszczenia(self.result.readings, DEKLARACJA)
        ]

    @property
    def morfologia(self) -> list[tuple[OdczytaniaFormy, ...]]:
        """Czym formy stoją w każdym odczytaniu: wpis na streszczenie z :attr:`readings`.

        Wiersz dostaje forma czytana więcej niż jednym sposobem, a odczytania w
        nim licencjonują ją w tym kształcie (:attr:`olski.parse.Leaf.odczytania`);
        wiersze składa :func:`olski.werdykt.wykazy._pod_streszczeniem`,
        a nad streszczeniem, które zbiera kilka kształtów,
        bierze odczytania z każdego z nich.
        Wpisów jest tyle, ile streszczeń, więc nad zdaniem urwanym na
        :data:`olski.parse.MAX_READINGS` mówią one o odczytaniach wypisanych.

        Zdanie bez ani jednego odczytania dostaje jeden wpis, a w nim każde
        odczytanie każdej formy (:func:`olski.werdykt.wykazy._morfologia_zdania`):
        odsiać ich nie ma czym.
        Rozstrzyga się to tutaj, a nie w wydruku, bo wydruki są dwa
        (``olski/check.py`` i ``witryna/werdykty.py``) i rozjechałyby się po cichu.
        """
        if self.result.rejected or not self.punktowane:
            return [_morfologia_zdania(self.text)]
        return [
            _pod_streszczeniem(drzewa)
            for _streszczenie, drzewa in streszczone(self.result.readings, DEKLARACJA)
        ]

    @property
    def rachunki(self) -> list[tuple[tuple[str, int], ...]]:
        """Za co płaci każde odczytanie: wpis na streszczenie z :attr:`readings`.

        Wychodzą stąd pozycje policzone, a sumę liczy z nich ten, kto ją pokazuje
        (:func:`olski.cennik.razem`): jest nią miejsce w kolejce odczytań,
        bo las porządkuje je sumą cennika po całym drzewie.

        Streszczenie zbiera czasem kilka kształtów, a rachunek jest tego, który
        wyszedł z lasu pierwszy, czyli tego, przez którego to streszczenie stoi
        tam, gdzie stoi.
        """
        return [
            cennik.rachunek(koszty_drzewa(drzewa[0]))
            for _streszczenie, drzewa in streszczone(self.result.readings, DEKLARACJA)
        ]

    @property
    def żądania(self) -> list[tuple[Żądanie, ...]]:
        """Czego czasownik żąda od obsadzonych pozycji: wpis na streszczenie z :attr:`readings`.

        Po co ta odpowiedź autorowi i czego ona nie mówi, wywodzi
        ``olski/żądania.py``; wpis jest na streszczenie z tego samego powodu, co
        przy :attr:`morfologia`, i grupuje go to samo pytanie o las.

        Warunku na zdanie odrzucone nie ma i nie ma go czemu stawiać: pozycję
        obsadza czytanie, a takie zdanie nie ma ani jednego, więc lista wychodzi
        stąd pusta sama. Morfologia ma tam wpis, bo mówi o formach, a nie o rolach.
        """
        return [
            _żądania_streszczenia(drzewa)
            for _streszczenie, drzewa in streszczone(self.result.readings, DEKLARACJA)
        ]

    @property
    def rozbieżne(self) -> list[Rozbieżność]:
        """Konstytuenty rozbieżne, którym streszczenia naprawdę się różnią.

        Jedno streszczenie znaczy, że streszczenie tej różnicy nie widzi
        (:class:`Rozbieżność`), a wypisane byłoby wierszem bez treści.
        Warunek stoi tu raz na oba wydruki, na wiersz poleceń i na witrynę,
        bo napisany dwa razy rozjechałby się po cichu.
        """
        return [r for r in self.result.rozbieżności if len(r.czytania) > 1]

    def explain(self, brak_odczytania: str = BRAK_ODCZYTANIA) -> str:
        """Co narzędzie ma o tym zdaniu do powiedzenia, jednym wierszem.

        Nazwa braku przychodzi argumentem, bo dwa tryby nazywają go różnie, a
        mówią pod obiema nazwami to samo o analizie, więc powód stoi tu raz.
        Bierze ją samo zdanie odrzucone: poprawka jednego znaku i napis, którego
        nic nie punktuje jako zdania, mówią autorowi co innego i idą przed nim.
        """
        #  Poprawka wyprzedza każde inne wyjaśnienie i wyprzedza je nad zdaniem
        #  odrzuconym tak samo jak nad napisem niedomkniętym: zatrzymanie mówi,
        #  dokąd doszła analiza, a poprawka mówi, co z tym zrobić.
        if self.naprawa is not None:
            return _naprawiony(self.naprawa)
        if self.status == FRAGMENT:
            return "to nie zdanie: nic go nie punktuje jako zdania"
        if self.result.valid:
            return _odczytań(1)
        if self.result.rejected:
            if self.nielicencjonowane:
                # Cudzysłów jest treścią: najczęstszą formą bez licencji jest
                # przecinek, a lista rozdzielana przecinkami gubi bez niego granice.
                formy = ", ".join(f"„{forma}”" for forma in self.nielicencjonowane)
                return f"{brak_odczytania}: żadna produkcja nie bierze {formy}"
            if self.result.furthest is None:
                #  Tak samo odmawia ``bloker`` w ``olski/pokrycie.py`` i z tego
                #  samego powodu: milczenie o zatrzymaniu czytałoby się tu jako
                #  zdanie o analizie, która doszła do końca.
                raise ValueError(
                    "wyjaśnienie odrzucenia nazywa miejsce zatrzymania, "
                    "a ten przebieg o zatrzymanie nie pytał (werdykt w olski/werdykt/zdanie.py)"
                )
            if self.zatrzymanie is None:
                return f"{brak_odczytania}: analiza dochodzi do końca, a nic nie domyka zdania"
            return f"{brak_odczytania}: analiza staje na „{self.zatrzymanie}”"
        przyłączenia = self.result.przyłączenia
        # Przekład idzie i tutaj (:func:`_nazwy_szkolne`), bo wiersz ten nie ma
        # nazywać roli, której lista czytań pod nim nie nazywa.
        różne = sorted(
            {
                nazwa
                for role in self.result.różniące
                # Przyłączenie nazwane niżej mówi o tej roli więcej niż sama jej
                # nazwa, więc wypisana obok byłaby tym samym zdaniem dwa razy.
                if not (przyłączenia and role == WYRAŻENIE_PRZYIMKOWE)
                for nazwa in _nazwy_szkolne(role)
            }
        )
        # Liczba i role wychodzą z lasu, więc granica wyliczania sięga listy
        # czytań i nie sięga tego wiersza: liczba jest liczbą, a nie „64+”.
        wiersz = _odczytań(self.result.ile)
        if różne:
            # Dwukropek oddziela nazwy od zdania: bez niego „różne w dopełnienie”
            # czyta się jak rzeczownik, którego przyimek nie odmienił.
            wiersz += f", różne w {'roli' if len(różne) == 1 else 'rolach'}: {', '.join(różne)}"
        return "; ".join(
            [
                wiersz,
                *map(_nierozstrzygnięte, przyłączenia),
                *map(_rozbieżny, self.result.rozbieżności),
            ]
        )

text instance-attribute

result instance-attribute

nielicencjonowane instance-attribute

zatrzymanie instance-attribute

naprawa instance-attribute

punktowane property

Czy tekst punktuje ten napis jako zdanie.

Mianownik pomiaru pyta o to, a nie o status, bo odpowiedź jest ta sama nad oboma werdyktami o napisie niepunktowanym i nie kosztuje rozbioru, którego kosztuje domknięcie (olski.werdykt.tekst.Podsumowanie).

zgłoszenie property

Czy narzędzie ma o tym zdaniu coś do powiedzenia.

Wydruk domyślny niesie dwa zgłoszenia: wieloznaczność oraz poprawkę jednego znaku, a znaleziskiem jest tylko druga (docs/subset.md#wieloznaczność-jest-odpowiedzią-a-nie-znaleziskiem). Zaimek wskazujący na dwie rzeczy naraz pada obok werdyktu, bo rzeczy nazywa zdanie obok (olski/odniesienia.py), więc tutaj go nie ma. Warunek stoi tu raz, bo pyta o niego wydruk nad każdym zdaniem osobno; olski.werdykt.tekst.Podsumowanie liczy każde z tych zgłoszeń nad tekstem i liczy je osobno.

Napis niepunktowany zostaje poza zgłoszeniem także wtedy, gdy poprawkę ma, bo nagłówek i pozycja listy dochodzą tu jako takie napisy i żadne z nich nie jest zdaniem, którego autor nie domknął (docs/extraction.md); wydruk pokazuje je do flagi --zatrzymania.

czytane property

Czy olski to zdanie czyta.

Nieczytane są trzy: zdanie odrzucone, napis, którego nic nie domyka, i fragment. O polszczyźnie żadnego z nich olski nie orzeka, więc wydruk milczy o nich do flagi (olski/check.py).

status property

Klasa, do której werdykt to zdanie liczy, czyli słowo pomiaru.

Wydruk komendy go nie podaje, bo dzieli zdania po liczbie odczytań, a nie po tym, czy narzędzie ma o zdaniu co powiedzieć (znalezisko). Czytają je pomiar pokrycia (olski/pokrycie.py), sondy w harness/ i znaczek na stronie (witryna/skrypt.js).

readings property

Streszczenia odczytań, każde raz (streszczenia).

Odczytanie jest krotką streszczeń, po jednym na zdanie składowe, więc wpisem tej listy jest krotka, a nie jedno streszczenie.

Lista jest po to, żeby pokazać różnicę między odczytaniami, a różnicę spoza zasięgu streszczenia nazywa wiersz o konstytuencie (_rozbieżny), więc powtórzony napis nie zostawia jej nienazwanej. Liczbę odczytań podaje las (Result.ile), więc skrócenie tej listy jej nie rusza.

morfologia property

Czym formy stoją w każdym odczytaniu: wpis na streszczenie z readings.

Wiersz dostaje forma czytana więcej niż jednym sposobem, a odczytania w nim licencjonują ją w tym kształcie (olski.parse.Leaf.odczytania); wiersze składa olski.werdykt.wykazy._pod_streszczeniem, a nad streszczeniem, które zbiera kilka kształtów, bierze odczytania z każdego z nich. Wpisów jest tyle, ile streszczeń, więc nad zdaniem urwanym na olski.parse.MAX_READINGS mówią one o odczytaniach wypisanych.

Zdanie bez ani jednego odczytania dostaje jeden wpis, a w nim każde odczytanie każdej formy (olski.werdykt.wykazy._morfologia_zdania): odsiać ich nie ma czym. Rozstrzyga się to tutaj, a nie w wydruku, bo wydruki są dwa (olski/check.py i witryna/werdykty.py) i rozjechałyby się po cichu.

rachunki property

Za co płaci każde odczytanie: wpis na streszczenie z readings.

Wychodzą stąd pozycje policzone, a sumę liczy z nich ten, kto ją pokazuje (olski.cennik.razem): jest nią miejsce w kolejce odczytań, bo las porządkuje je sumą cennika po całym drzewie.

Streszczenie zbiera czasem kilka kształtów, a rachunek jest tego, który wyszedł z lasu pierwszy, czyli tego, przez którego to streszczenie stoi tam, gdzie stoi.

żądania property

Czego czasownik żąda od obsadzonych pozycji: wpis na streszczenie z readings.

Po co ta odpowiedź autorowi i czego ona nie mówi, wywodzi olski/żądania.py; wpis jest na streszczenie z tego samego powodu, co przy morfologia, i grupuje go to samo pytanie o las.

Warunku na zdanie odrzucone nie ma i nie ma go czemu stawiać: pozycję obsadza czytanie, a takie zdanie nie ma ani jednego, więc lista wychodzi stąd pusta sama. Morfologia ma tam wpis, bo mówi o formach, a nie o rolach.

rozbieżne property

Konstytuenty rozbieżne, którym streszczenia naprawdę się różnią.

Jedno streszczenie znaczy, że streszczenie tej różnicy nie widzi (Rozbieżność), a wypisane byłoby wierszem bez treści. Warunek stoi tu raz na oba wydruki, na wiersz poleceń i na witrynę, bo napisany dwa razy rozjechałby się po cichu.

__init__(text, result, nielicencjonowane, zatrzymanie, naprawa)

explain(brak_odczytania=BRAK_ODCZYTANIA)

Co narzędzie ma o tym zdaniu do powiedzenia, jednym wierszem.

Nazwa braku przychodzi argumentem, bo dwa tryby nazywają go różnie, a mówią pod obiema nazwami to samo o analizie, więc powód stoi tu raz. Bierze ją samo zdanie odrzucone: poprawka jednego znaku i napis, którego nic nie punktuje jako zdania, mówią autorowi co innego i idą przed nim.

Source code in olski/werdykt/zdanie.py
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
def explain(self, brak_odczytania: str = BRAK_ODCZYTANIA) -> str:
    """Co narzędzie ma o tym zdaniu do powiedzenia, jednym wierszem.

    Nazwa braku przychodzi argumentem, bo dwa tryby nazywają go różnie, a
    mówią pod obiema nazwami to samo o analizie, więc powód stoi tu raz.
    Bierze ją samo zdanie odrzucone: poprawka jednego znaku i napis, którego
    nic nie punktuje jako zdania, mówią autorowi co innego i idą przed nim.
    """
    #  Poprawka wyprzedza każde inne wyjaśnienie i wyprzedza je nad zdaniem
    #  odrzuconym tak samo jak nad napisem niedomkniętym: zatrzymanie mówi,
    #  dokąd doszła analiza, a poprawka mówi, co z tym zrobić.
    if self.naprawa is not None:
        return _naprawiony(self.naprawa)
    if self.status == FRAGMENT:
        return "to nie zdanie: nic go nie punktuje jako zdania"
    if self.result.valid:
        return _odczytań(1)
    if self.result.rejected:
        if self.nielicencjonowane:
            # Cudzysłów jest treścią: najczęstszą formą bez licencji jest
            # przecinek, a lista rozdzielana przecinkami gubi bez niego granice.
            formy = ", ".join(f"„{forma}”" for forma in self.nielicencjonowane)
            return f"{brak_odczytania}: żadna produkcja nie bierze {formy}"
        if self.result.furthest is None:
            #  Tak samo odmawia ``bloker`` w ``olski/pokrycie.py`` i z tego
            #  samego powodu: milczenie o zatrzymaniu czytałoby się tu jako
            #  zdanie o analizie, która doszła do końca.
            raise ValueError(
                "wyjaśnienie odrzucenia nazywa miejsce zatrzymania, "
                "a ten przebieg o zatrzymanie nie pytał (werdykt w olski/werdykt/zdanie.py)"
            )
        if self.zatrzymanie is None:
            return f"{brak_odczytania}: analiza dochodzi do końca, a nic nie domyka zdania"
        return f"{brak_odczytania}: analiza staje na „{self.zatrzymanie}”"
    przyłączenia = self.result.przyłączenia
    # Przekład idzie i tutaj (:func:`_nazwy_szkolne`), bo wiersz ten nie ma
    # nazywać roli, której lista czytań pod nim nie nazywa.
    różne = sorted(
        {
            nazwa
            for role in self.result.różniące
            # Przyłączenie nazwane niżej mówi o tej roli więcej niż sama jej
            # nazwa, więc wypisana obok byłaby tym samym zdaniem dwa razy.
            if not (przyłączenia and role == WYRAŻENIE_PRZYIMKOWE)
            for nazwa in _nazwy_szkolne(role)
        }
    )
    # Liczba i role wychodzą z lasu, więc granica wyliczania sięga listy
    # czytań i nie sięga tego wiersza: liczba jest liczbą, a nie „64+”.
    wiersz = _odczytań(self.result.ile)
    if różne:
        # Dwukropek oddziela nazwy od zdania: bez niego „różne w dopełnienie”
        # czyta się jak rzeczownik, którego przyimek nie odmienił.
        wiersz += f", różne w {'roli' if len(różne) == 1 else 'rolach'}: {', '.join(różne)}"
    return "; ".join(
        [
            wiersz,
            *map(_nierozstrzygnięte, przyłączenia),
            *map(_rozbieżny, self.result.rozbieżności),
        ]
    )

werdykt(zdanie, segmenty, grammar=None, zatrzymanie=True)

Werdykt o zdaniu już zsegmentowanym, wraz z całym podsumowaniem.

Segmenty przychodzą argumentem, a nie powstają tutaj, bo zależą od napisu, a nie od gramatyki: kto pyta o jedno zdanie kilka gramatyk — sonda różnicowa nad prozą — segmentuje je raz i pyta tyle razy, ile ma wariantów.

Zatrzymanie jest najdroższym z podsumowań i jedynym, które wolno pominąć. Nad zdaniem odrzuconym przechodzi tablicę drugi raz i unifikuje przy tym przebyte ciała (olski.parse.podsumuj), a nad prozą, której olski w większości nie wyprowadza, odrzuconych jest osiem zdań na dziesięć, więc waży w takim przebiegu więcej niż każde inne podsumowanie. Czytają je Verdict.explain i kolejka blokerów (olski/pokrycie.py); kto go nie czyta, prosi o werdykt bez niego.

Flagą, a nie pytaniem leniwym: Result trzymający las liczyłby punkt przy pierwszym pytaniu, ale przebieg nad bankiem drzew pyta o niego przy każdym zdaniu odrzuconym, a las porzuca rozmyślnie, bo waży tyle, ile jego tablica (zmierz_zdanie w harness/pomiar.py).

Napis bez znaku kończącego pyta o zatrzymanie mimo flagi, bo od niego zależy wtedy sam status: poprawki domykającej szuka się nad analizą, która doszła do końca (olski.werdykt.odrzucone._naprawa), a nad napisem punktowanym nie szuka się jej wcale.

Source code in olski/werdykt/zdanie.py
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
def werdykt(
    zdanie: str,
    segmenty: list[Segment],
    grammar: Grammar | None = None,
    zatrzymanie: bool = True,
) -> Verdict:
    """Werdykt o zdaniu już zsegmentowanym, wraz z całym podsumowaniem.

    Segmenty przychodzą argumentem, a nie powstają tutaj, bo zależą od napisu, a
    nie od gramatyki: kto pyta o jedno zdanie kilka gramatyk — sonda różnicowa
    nad prozą — segmentuje je raz i pyta tyle razy, ile ma wariantów.

    Zatrzymanie jest najdroższym z podsumowań i jedynym, które wolno pominąć.
    Nad zdaniem odrzuconym przechodzi tablicę drugi raz
    i unifikuje przy tym przebyte ciała (:func:`olski.parse.podsumuj`),
    a nad prozą, której olski w większości nie wyprowadza,
    odrzuconych jest osiem zdań na dziesięć,
    więc waży w takim przebiegu więcej niż każde inne podsumowanie.
    Czytają je :meth:`Verdict.explain` i kolejka blokerów (``olski/pokrycie.py``);
    kto go nie czyta, prosi o werdykt bez niego.

    Flagą, a nie pytaniem leniwym: ``Result`` trzymający las liczyłby punkt przy
    pierwszym pytaniu, ale przebieg nad bankiem drzew pyta o niego przy każdym
    zdaniu odrzuconym, a las porzuca rozmyślnie, bo waży tyle, ile jego tablica
    (``zmierz_zdanie`` w ``harness/pomiar.py``).

    Napis bez znaku kończącego pyta o zatrzymanie mimo flagi, bo od niego zależy
    wtedy sam status: poprawki domykającej szuka się nad analizą, która doszła
    do końca (:func:`olski.werdykt.odrzucone._naprawa`),
    a nad napisem punktowanym nie szuka się jej wcale.
    """
    grammar = grammar or GRAMMAR
    pytane = zatrzymanie or not SENTENCE_CLOSE.search(zdanie)
    result = parse(grammar, segmenty, deklaracja=DEKLARACJA, zatrzymanie=pytane)
    stanęło = na_czym_stanęło(segmenty, result.furthest) if pytane else None
    #  Brak formy jest dojściem do końca dopiero wtedy, gdy pytano:
    #  bez pytania ``stanęło`` jest puste także nad analizą, która stanęła.
    doszło_do_końca = pytane and stanęło is None
    nielicencjonowane = bez_licencji(segmenty, grammar)
    return Verdict(
        text=zdanie,
        result=result,
        nielicencjonowane=nielicencjonowane,
        zatrzymanie=stanęło.form if stanęło is not None else None,
        naprawa=_naprawa(zdanie, grammar, result.rejected, nielicencjonowane, doszło_do_końca),
    )

dalsze_zatrzymania(verdict, grammar=None)

Zatrzymania tego zdania poza tym, które nazwał już werdykt.

Zdanie z czytaniem nie stanęło nigdzie, więc krotka jest wtedy pusta, i tak samo pusta jest nad fragmentem. Segmentacja idzie tu drugi raz, bo werdykt segmentów nie niesie (werdykt).

Pierwsze zatrzymanie bierze się z Result.furthest, a nie z rozbioru: werdykt tę liczbę już policzył, a rozbiór po całym zdaniu jest najdroższy z całej pętli. Węzeł stamtąd nazywa tutaj tę samą krawędź, bo oba wołania olski.segmentacja.morphology biorą ten sam napis.

Source code in olski/werdykt/zdanie.py
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
def dalsze_zatrzymania(verdict: Verdict, grammar: Grammar | None = None) -> tuple[str, ...]:
    """Zatrzymania tego zdania poza tym, które nazwał już werdykt.

    Zdanie z czytaniem nie stanęło nigdzie, więc krotka jest wtedy pusta, i tak
    samo pusta jest nad fragmentem. Segmentacja idzie tu drugi raz, bo werdykt
    segmentów nie niesie (:func:`werdykt`).

    Pierwsze zatrzymanie bierze się z ``Result.furthest``, a nie z rozbioru:
    werdykt tę liczbę już policzył,
    a rozbiór po całym zdaniu jest najdroższy z całej pętli.
    Węzeł stamtąd nazywa tutaj tę samą krawędź,
    bo oba wołania :func:`olski.segmentacja.morphology` biorą ten sam napis.
    """
    if not verdict.punktowane or not verdict.result.rejected:
        return ()
    if verdict.result.furthest is None:
        #  Tak samo odmawiają ``Verdict.explain`` i ``bloker`` (``olski/pokrycie.py``):
        #  krotka pusta czytałaby się jak zdanie stające raz.
        raise ValueError(
            "zatrzymania dalsze liczą się od pierwszego, "
            "a ten przebieg o zatrzymanie nie pytał (werdykt w olski/werdykt/zdanie.py)"
        )
    segmenty = morphology(verdict.text)
    stanęło = na_czym_stanęło(segmenty, verdict.result.furthest)
    return _od_zatrzymania(segmenty, grammar or GRAMMAR, stanęło)[1:]

niespełnione_żądania(verdict, deklaracja=OSOBY_PROJEKTU)

Pozycje, w których czasownik żąda kogoś, a nikt w nich nie stoi.

Obie połowy pytania spotykają się tutaj: żądanie przychodzi z pliku żądań (olski.żądania.żąda_osoby), a spełnienie z deklaracji projektu (olski/osoby.py). Wiersz zostaje po tej pozycji, której żądania nie spełnia nic z tego, czym jest jej głowa.

Wiersz jest o zdaniu, a nie o odczytaniu, i tym różni się ten wykaz od Verdict.żądania. Pozycję obsadza czytanie, więc wiersz mówi tyle, że w którymś z nich stoi rzecz tam, gdzie czasownik żąda kogoś. Zdanie wieloznaczne ma czytań kilkanaście, a wiersz o jednej pozycji w każdym z nich ten sam, więc wykaz na odczytanie kazałby przeczytać kilkanaście kopii jednego wiersza.

Source code in olski/werdykt/zdanie.py
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
def niespełnione_żądania(
    verdict: Verdict, deklaracja: Osoby = OSOBY_PROJEKTU
) -> tuple[Żądanie, ...]:
    """Pozycje, w których czasownik żąda kogoś, a nikt w nich nie stoi.

    Obie połowy pytania spotykają się tutaj: żądanie przychodzi z pliku żądań
    (:func:`olski.żądania.żąda_osoby`), a spełnienie z deklaracji projektu
    (``olski/osoby.py``). Wiersz zostaje po tej pozycji, której żądania nie
    spełnia nic z tego, czym jest jej głowa.

    **Wiersz jest o zdaniu, a nie o odczytaniu**, i tym różni się ten wykaz od
    :attr:`Verdict.żądania`. Pozycję obsadza czytanie, więc wiersz mówi tyle,
    że w którymś z nich stoi rzecz tam, gdzie czasownik żąda kogoś. Zdanie
    wieloznaczne ma czytań kilkanaście, a wiersz o jednej pozycji w każdym z nich
    ten sam, więc wykaz na odczytanie kazałby przeczytać kilkanaście kopii
    jednego wiersza.
    """
    return tuple(
        żądanie
        for żądanie in _zwinięte(żądanie for tabela in verdict.żądania for żądanie in tabela)
        if żąda_osoby(żądanie.klasy) and not deklaracja.nazywają(żądanie.lematy)
    )