Przejdź do treści

olski.check

Sprawdzenie tekstu wobec gramatyki, z wiersza poleceń.

Komenda bierze plik, który autor napisał, i prozę wyjmuje z niego sama (olski.wejście.proza), więc dokumentu nikt nie przepisuje wcześniej na zwykły tekst.

Wydruk zgłasza znaleziska i milczy o zdaniu, o którym nie ma nic do powiedzenia (_wiersze), a ile tego milczenia było, mówi ostatni wiersz przebiegu (olski.werdykt.Podsumowanie).

T = TypeVar('T') module-attribute

MIĘDZY_ODCZYTANIAMI = ' | ' module-attribute

ALBO = ' albo ' module-attribute

KLASA_NIENAZWANA = 'klasy, której olski nie nazywa' module-attribute

DOMYSŁ = '?' module-attribute

czytanie(streszczenie, wcięcie='')

Wiersze jednego czytania: po jednym na zdanie składowe.

Kreska otwiera czytanie, a składowe następne stoją pod nim bez niej, bo lista liczy czytania: kreska przy każdym składowym mówiłaby, że zdanie o dwóch składowych i jednym czytaniu ma czytania dwa.

Publiczna, bo czytanie pierwsze wypisuje obok tej komendy sonda cen (harness/cena.py), a dwa wydruki jednego czytania nie dałyby się porównać.

Source code in olski/check.py
75
76
77
78
79
80
81
82
83
84
85
86
def czytanie(streszczenie: tuple[dict[str, str], ...], wcięcie: str = "") -> Iterator[str]:
    """Wiersze jednego czytania: po jednym na zdanie składowe.

    Kreska otwiera czytanie, a składowe następne stoją pod nim bez niej,
    bo lista liczy czytania: kreska przy każdym składowym mówiłaby,
    że zdanie o dwóch składowych i jednym czytaniu ma czytania dwa.

    Publiczna, bo czytanie pierwsze wypisuje obok tej komendy sonda cen
    (``harness/cena.py``), a dwa wydruki jednego czytania nie dałyby się porównać.
    """
    for numer, składowe in enumerate(streszczenie):
        yield f"{wcięcie}- {_role(składowe)}" if numer == 0 else f"{wcięcie}  {_role(składowe)}"

main(argv=None)

Source code in olski/check.py
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
def main(argv: Sequence[str] | None = None) -> int:
    parser = argparse.ArgumentParser(
        prog="olski-check",
        description="Sprawdź zdania polskiego tekstu: zgłoś wieloznaczne, "
        "a o zdaniach, których olski nie czyta, milcz do flagi.",
    )
    parser.add_argument("paths", nargs="*", help="pliki polskiego tekstu albo dokumenty")
    parser.add_argument("-c", "--text", help="sprawdź ten tekst zamiast pliku")
    parser.add_argument(
        "--readings",
        action="store_true",
        help="pokaż, co stoi w której roli, raz na streszczenie odczytania",
    )
    parser.add_argument(
        "--koszt",
        action="store_true",
        help="pokaż, czym każde odczytanie jest nacechowane i ile to kosztuje",
    )
    parser.add_argument(
        "--rozstrzygaj",
        action="store_true",
        help="obok werdyktu pokaż, co osobna warstwa mówi o przyłączeniach",
    )
    parser.add_argument(
        "--morfologia",
        action="store_true",
        help="pokaż lemat i znacznik form, czyli czym stoją w odczytaniu",
    )
    parser.add_argument(
        "--żądania",
        action="store_true",
        help="pokaż, czego czasownik żąda od słowa stojącego w jego pozycji",
    )
    parser.add_argument(
        "--osoby",
        action="store_true",
        help="pokaż pozycje, w których czasownik żąda kogoś, a stoi w nich rzecz",
    )
    parser.add_argument(
        "--zatrzymania",
        action="store_true",
        help="pokaż zdania, których olski nie czyta, wraz z każdym miejscem, "
        "na którym staje analiza",
    )
    args = parser.parse_args(argv)

    if not args.paths and args.text is None:
        parser.print_usage(sys.stderr)
        return 2

    sources: list[tuple[str, str]] = []
    if args.text is not None:
        sources.append(("<text>", args.text))
    for raw in args.paths:
        path = Path(raw)
        try:
            sources.append((raw, proza(path)))
        except (OSError, UnicodeDecodeError) as error:
            print(f"olski-check: nie udało się przeczytać {raw}: {error}", file=sys.stderr)
            return 2

    #  Świadkowie powstają raz na przebieg, a nie raz na zdanie: tabela skłonności
    #  wchodzi z pliku, a dokument ma tyle zdań, ile ma.
    świadkowie = domyślni() if args.rozstrzygaj else None

    wszystkie: list[Verdict] = []
    niejasnych = 0
    for name, text in sources:
        #  Sąsiedztwa liczą się dla całego tekstu naraz, bo akapit jest jego
        #  własnością, a nie zdania: zdanie samo nie wie, co stoi przed nim.
        #  Z tego samego powodu liczą się tu odniesienia.
        werdykty = check(text)
        wszystkie += werdykty
        konteksty = sąsiedztwa(text) if świadkowie is not None else [PUSTE] * len(werdykty)
        odniesienia = niejasne_odniesienia(text, werdykty)
        niejasnych += sum(1 for zgłoszenia in odniesienia if zgłoszenia)
        for verdict, sąsiedztwo, zgłoszenia in zip(
            werdykty, konteksty, odniesienia, strict=True
        ):
            wiersze = list(_wiersze(verdict, args, świadkowie, sąsiedztwo, zgłoszenia))
            if not wiersze:
                continue
            print(f"{name}: {verdict.text}")
            for wiersz in wiersze:
                print(f"{' ' * (len(name) + 2)}{wiersz}")

    podsumowanie = Podsumowanie.z_werdyktów(wszystkie, niejasnych)
    print(podsumowanie.explain())
    #  Kod wyjścia niesie znaleziska, a nie milczenie
    #  (docs/subset.md#wieloznaczność-jest-znaleziskiem-a-nie-definicją-olskiego).
    return 0 if podsumowanie.znalezisk == 0 else 1