
OPIS / Pollan
Kompletny język programowania z polską warstwą słów kluczowych i deterministyczną semantyką.
- PROJECT
- CODE-044
- JĘZYK IMPLEMENTACJI
- RUST · 17 CRATE’ÓW
- FUNKCJE WBUDOWANE
- 167
- TESTY
- ~294 · 43 ADR
- DOJRZAŁOŚĆ
- 1.0 (POZIOM C)
- STATUS
- UKOŃCZONY
- DATA
- 19 sierpnia 2026
Uniwersalny język o czytelnej, opisowej składni i formalnej semantyce. Nie zależy od modeli językowych — każda poprawna konstrukcja ma dokładnie określone znaczenie; AI może generować kod, ale to kompilator nadaje mu sens. Działający potok: interpreter oraz kompilacja natywna przez OIR → C → clang.
Jak wygląda program w OPIS-ie
Najkrótszy sensowny program pokazuje trzy rzeczy naraz: deklarację zmiennej, konwersję typu i wypisanie wyniku. Składnia jest opisowa — słowa kluczowe to polskie słowa, a nie tłumaczenia angielskich skrótów.
program "Pierwszy program"
zmienna wiek = 20
napisz "Mam " + tekst(wiek) + " lat"
koniec programu
Zwróć uwagę na tekst(wiek). Funkcja napisz oczekuje tekstu, a wiek jest liczbą — język nie robi cichej konwersji, bo cicha konwersja jest źródłem błędów, których nie widać w kodzie. To decyzja projektowa, nie niedopatrzenie.
Typy i deklaracje
OPIS ma pięć typów podstawowych: liczba, liczba_calkowita, tekst, logiczna i nic. Typ można podać jawnie albo pozwolić kompilatorowi go wywnioskować z wartości początkowej.
zmienna licznik = 0 # wywnioskowany: liczba_calkowita
zmienna cena jako liczba = 9.99 # jawny
stala VAT = 0.23 # stała — nie da się zmienić
ustaw licznik na licznik + 1 # przypisanie po deklaracji
Rozdzielenie zmienna (tworzę) od ustaw … na (zmieniam) jest celowe. W większości języków obie operacje wyglądają identycznie, przez co literówka w nazwie tworzy nową zmienną zamiast zgłosić błąd. Tutaj ustaw na nieistniejącej nazwie jest błędem kompilacji.
Sterowanie przepływem
jezeli n <= 1 wtedy
zwroc 1
inaczej
zwroc n * silnia(n - 1)
koniec jezeli
dla i od 1 do 100 wykonuj
ustaw suma na suma + i
koniec dla
dopoki licznik < 10 wykonuj
ustaw licznik na licznik + 1
jezeli licznik == 5 wtedy
kontynuuj
koniec jezeli
koniec dopoki
dla kazdego element w lista wykonuj
napisz tekst(element)
koniec dla
Każdy blok domyka się jawnie: koniec jezeli, koniec dla, koniec dopoki. Jest to wielomówne, ale usuwa całą klasę pomyłek z zagnieżdżaniem — i czyni kod czytelnym dla kogoś, kto nigdy wcześniej nie programował.
Funkcje i procedury
Funkcja zwraca wartość i musi zadeklarować jej typ. Procedura nie zwraca nic. To rozróżnienie jest w składni, a nie w konwencji nazewniczej.
funkcja silnia(n jako liczba_calkowita) zwraca liczba_calkowita
jezeli n <= 1 wtedy
zwroc 1
koniec jezeli
zwroc n * silnia(n - 1)
koniec funkcji
funkcja brutto(netto jako liczba) zwraca liczba
zwroc netto * (1.0 + VAT)
koniec funkcji
napisz "silnia(10) = " + tekst(silnia(10))
napisz "brutto(100) = " + tekst(brutto(100.0))
Struktury, wyliczenia i dopasowanie wzorców
Tu widać, że OPIS nie jest językiem zabawkowym. Wyliczenia niosą wartości, a wybierz/gdy wymusza wyczerpujące dopasowanie — pominięcie przypadku jest błędem kompilacji, nie niespodzianką w czasie działania.
struktura Punkt
x jako liczba_calkowita
y jako liczba_calkowita
koniec struktury
wyliczenie Wynik
Sukces(wartosc)
Blad(powod)
koniec wyliczenia
funkcja podziel(a jako liczba_calkowita, b jako liczba_calkowita) zwraca Wynik
jezeli b == 0 wtedy
zwroc Wynik.Blad("dzielenie przez zero")
koniec jezeli
zwroc Wynik.Sukces(a / b)
koniec funkcji
zmienna p = Punkt(3, 4)
ustaw p.x na 10
napisz "suma pol: " + tekst(p.x + p.y)
wybierz podziel(20, 4)
gdy Sukces(wart)
napisz "ok: " + tekst(wart)
gdy Blad(powod)
napisz "blad: " + powod
koniec wybierz
To jest ten sam wzorzec, który w językach funkcyjnych nazywa się typem wynikowym. Błąd nie jest wyjątkiem lecącym w górę stosu — jest wartością, którą trzeba obsłużyć, żeby program się skompilował.
Obsługa błędów wykonania
sprobuj
zmienna dane = wczytaj_plik("konfiguracja.json")
zmienna config = json_parsuj(dane)
blad e
napisz "nie udalo sie wczytac: " + e
wreszcie
napisz "koniec proby"
koniec sprobuj
Typy złożone i funkcje wyższego rzędu
zmienna liczby jako lista<liczba_calkowita> = [1, 2, 3, 4, 5]
zmienna ceny jako slownik<tekst, liczba> = {"chleb": 4.50, "mleko": 3.20}
zmienna podwojone = mapuj(liczby, funkcja(x) zwraca liczba_calkowita
zwroc x * 2
koniec funkcji)
zmienna parzyste = filtruj(liczby, funkcja(x) zwraca logiczna
zwroc x % 2 == 0
koniec funkcji)
zmienna suma = redukuj(liczby, 0, funkcja(a, b) zwraca liczba_calkowita
zwroc a + b
koniec funkcji)
Generyki są egzekwowane. lista<liczba_calkowita> nie przyjmie tekstu, a kompilator powie o tym w miejscu przypisania, nie przy pierwszym użyciu.
Grafika i pętla gry
Programy okienkowe uruchamia się innym poleceniem (opis okno plik.pol) i piszą się wokół dwóch procedur: krok liczy stan, rysuj go pokazuje.
program "Odbijajaca sie pilka"
zmienna x = 100.0
zmienna y = 100.0
zmienna dx = 3.0
zmienna dy = 2.0
procedura krok(czas jako liczba)
ustaw x na x + dx
ustaw y na y + dy
jezeli x < 20.0 lub x > 780.0 wtedy
ustaw dx na -dx
koniec jezeli
jezeli y < 20.0 lub y > 580.0 wtedy
ustaw dy na -dy
koniec jezeli
koniec procedury
procedura rysuj()
tlo(17, 19, 21)
kolor(82, 210, 115)
kolo(x, y, 20.0)
kolor(241, 235, 221)
napis("OPIS", 20.0, 30.0)
koniec procedury
koniec programu
Dostępne są prymitywy rysowania (prostokąt, koło, elipsa, linia, łuk, trójkąt, wielokąt, gradient, piksel), gładkie fonty TTF w trzech odmianach, obrazy, obsługa myszy i klawiatury, widżety oraz dźwięk z silnikiem MML. Na tej warstwie powstały działające przykłady: tetris, szachy z grafiką, symulacje i arkusz kalkulacyjny.
Dwie ścieżki wykonania
Ten sam plik uruchamia się na dwa sposoby i to jest sedno architektury projektu:
# interpreter — wyrocznia, definiuje znaczenie
cargo run -p opis-cli --bin opis -- run examples/dane.pol
# kompilacja natywna — OIR → C → clang
cargo run -p opis-cli --bin opis -- buduj examples/dane.pol
# program okienkowy
cargo run --release -p opis-cli --bin opis -- okno examples/tetris.pol
# debugger z punktami przerwania
cargo run -p opis-cli --bin opis -- debuguj examples/dane.pol
Interpreter jest odniesieniem: jeśli wersja skompilowana zachowuje się inaczej, błąd jest w kompilatorze albo — częściej — w specyfikacji, która czegoś nie dopowiada. Ta para wyłapała większość niejednoznaczności w semantyce języka.
Narzędzia wokół języka
Sam kompilator nie wystarczy, żeby ktokolwiek chciał w danym języku pisać. Dlatego powstały: debugger z krokowaniem i podglądem zmiennych, formatter (opis fmt), serwer języka LSP (opisd) dający podpowiedzi i diagnostykę w edytorze, system modułów (uzyj) oraz kompilacja do samodzielnego pliku wykonywalnego.
Dokumentacja liczy 61 rozdziałów składanych do jednego PDF-a — od pierwszego programu po referencję wszystkich 167 funkcji wbudowanych, listę słów zarezerwowanych, katalog błędów i ściągę składniową.
PROBLEM
Nauka programowania po polsku kończy się zwykle na pseudokodzie w podręczniku. Realne języki mają angielskie słowa kluczowe, a próby ich tłumaczenia dają zabawki bez bibliotek, bez narzędzi i bez możliwości zrobienia czegokolwiek poza ćwiczeniem.
Drugi problem jest świeższy: język, którego semantykę „rozumie” dopiero model językowy, nie jest językiem programowania — jest promptem.
POMYSŁ
Zbudować pełny język z polskimi słowami kluczowymi i formalną, deterministyczną semantyką, a do tego komplet narzędzi, których oczekuje się od poważnego języka: bibliotekę standardową, debugger, formatter, serwer LSP, moduły i kompilację natywną.
PROJEKT
Rdzeń obejmuje zmienne i stałe, typy podstawowe, warunki, pętle dopoki, dla i dla kazdego, funkcje, procedury i rekurencję. Typy złożone to listy i słowniki z egzekwowanymi generykami, struktury, metody z UFCS, dziedziczenie, cechy, wyliczenia oraz wyczerpujące dopasowanie wzorców przez wybierz/gdy.
Obsługa błędów ma pełną konstrukcję sprobuj … blad … wreszcie, łapiącą również błędy wykonania. Biblioteka standardowa pokrywa matematykę, teksty, wejście z konsoli, pliki, JSON, datę i czas oraz sieć HTTP.
Osobną, dużą częścią jest grafika: okno, pętla gry, prymitywy rysowania, gładkie fonty TTF, obrazy, mysz, klawiatura, widżety oraz dźwięk z silnikiem MML.
Narzędzia dopełniają obraz: debugger z punktami przerwania i podglądem zmiennych, kompilacja natywna, system modułów, serwer języka LSP oraz formatter. To ta warstwa oddziela język od ćwiczenia — bez debuggera i podpowiedzi w edytorze nikt nie napisze w nim niczego dłuższego niż przykład z podręcznika.
REALIZACJA
Implementacja liczy siedemnaście crate’ów w Ruście, 167 funkcji wbudowanych, 56 przykładów i 43 decyzje architektoniczne zapisane jako ADR. Bramka jakości obejmuje formatowanie, clippy i około 294 testy.
Kompilacja natywna idzie ścieżką OIR → C → clang, a obok działa interpreter pełniący rolę wyroczni: to on definiuje, co program ma robić, i względem niego weryfikowana jest wersja kompilowana.
EFEKT
W przykładach leżą działające programy: szachy z grafiką, tetris, arkusz kalkulacyjny, symulacje i przykład uczenia maszynowego. Powstała też pełna instrukcja — 61 rozdziałów w manual_src, składanych do PDF-a.
Deklaracja „język nie zależy od LLM” jest tu decyzją projektową, nie deklaracją ideową. Model może wygenerować kod w OPIS-ie, ale znaczenie tego kodu wynika ze specyfikacji i kompilatora — jest sprawdzalne, powtarzalne i możliwe do zdebugowania. To różnica między językiem programowania a interfejsem konwersacyjnym.
GALERIA
04 ZDJĘĆOPIS — pulpit systemowy napisany w całości w tym języku · zrzut z projektu
Pollan — szachy napisane w języku OPIS · zrzut z projektu
Pollan — grafika 2D generowana z kodu · zrzut z projektu
Pollan — okładka instrukcji języka · zrzut z projektu
WNIOSKI
Interpreter jako wyrocznia okazał się najlepszą decyzją w projekcie. Przy dwóch niezależnych ścieżkach wykonania każda rozbieżność wskazuje miejsce, w którym specyfikacja jest niedopowiedziana — a nie miejsce, w którym trzeba zgadywać, która wersja ma rację.


