Hacker Lang
Dokumentacja v2
Język programownia zaprojektowany pod HackerOS. Kompiluje się do binarki lub można uruchamić w wydajnym runtime z jit.
Instalacja i uruchomienie
Hacker Lang jest wbudowany w HackerOS..
.hl i skompilowany bytecode.# Uruchom plik .hl hl run moj_skrypt.hl Skompiluj do wydajnej binarki hl compile moj_skrypt.hl # Uruchom z verbose (pokazuje bytecode i disassembly) hl run moj_skrypt.hl --verbose # Tylko analiza statyczna bez wykonania hl check moj_skrypt.hl # Zainstaluj bibliotekę bit install nazwa-liba # Zainstaluj plugin bit install plugin nazwa-pluginu
Struktura pliku .hl
Każdy plik hacker-lang jest przetwarzany linia po linii. Kolejność sekcji jest elastyczna, ale konwencjonalna struktura wygląda tak:
! ─── 1. Zależności systemowe ──────────────────────── // curl jq git ! ─── 2. Biblioteki ────────────────────────────────── #<core/io:2.0> #<source/utils> ! ─── 3. Zmienne globalne i stałe ───────────────────── @APP_NAME="MójSkrypt" %VERSION="2.0.0" ! ─── 4. Definicje funkcji ─────────────────────────── :init def log "Inicjalizacja $APP_NAME v$VERSION" done ! ─── 5. Ciało główne ──────────────────────────────── .init end 0
!) są ignorowane.Komentarze
Dwa rodzaje komentarzy: liniowe i blokowe. Są pomijane przez interpreter bytecode, ale PLSA może je indeksować do dokumentacji.
| Składnia | Typ | Opis |
|---|---|---|
| ! tekst | liniowy | Cała linia ignorowana. Musi być na początku (po trimie). |
| !! | blokowy | Przełącza tryb komentarza blokowego (otwiera/zamyka). Wszystkie linie między !! są ignorowane. |
! To jest komentarz liniowy — cała linia ignorowana @AUTOR="Jan" !! To jest blok komentarza. Może zajmować wiele linii bez ograniczeń. Interpreter całkowicie to pomija. !! log "Ten kod jest wykonywalny"
! musi być pierwszym znakiem linii (po ewentualnych białych znakach). Nie można dodać komentarza na końcu linii z kodem — log "abc" ! komentarz jest błędem składni.Zmienne i stałe
v9: % stałeHacker Lang v2 rozróżnia trzy kategorie zmiennych. Każda ma inne zachowanie i zakres widoczności.
WIELKIE_LITERY.! ─── Zmienne globalne (env) ────────────────────── @HOME_DIR="/home/user" @MAX_RETRY=3 @APP="backup-tool" ! ─── Stałe (const) — v9 ───────────────────────── %API_VERSION="v2" %MAX_CONN=100 %BASE_URL="https://api.example.com" ! ─── Zmienne lokalne ──────────────────────────── $data="$(date +%Y-%m-%d)" $liczba=42 $wynik="$(hostname)" ! ─── Zmienna raw — bez rozwijania $() ─────────── ~$szablon="$(to nie zostanie wykonane)" ! ─── Użycie w komendach ───────────────────────── > echo "Data: $data, Max: $MAX_CONN"
Zaawansowane przykłady
! Obliczenia i przechwyt wyjścia $rozmiar="$(du -sh /home | cut -f1)" $pid="$(pgrep nginx | head -1)" $uptime="$(uptime -p)" ! Arytmetyka $suma=$(( 10 + 20 )) $proc=$(( $suma * 100 / 30 )) ! Stałe z obliczeniami %TIMEOUT=30 %MAX_SIZE="$(( 1024 * 1024 * 512 ))" ! Sprawdzenie czy zmienna ustawiona ? -z "$API_KEY" > log "BŁĄD: API_KEY nie ustawiony!" ? -n "$DATABASE_URL" > log "DB: $DATABASE_URL"
%KEY=val ustawia zmienną środowiskową, którą VM zapamiętuje w zbiorze stałych. Przy próbie nadpisania przez @KEY=... lub $KEY=... VM wypisuje ostrzeżenie. Stałe są idealne dla konfiguracji (URL, wersje, limity).Komendy
Pięć prefiksów do uruchamiania komend systemowych. Różnią się sposobem interpolacji zmiennych i izolacją środowiska.
| Prefiks | Typ | Opis |
|---|---|---|
| > cmd | RawSub | Komenda z rozwijaniem $VAR, $(cmd). Wykonywana w bieżącym kontekście. |
| |> cmd | RawSub | Identyczne z > — alternatywna notacja pipe-like. |
| >> cmd | RawNoSub | Komenda bez rozwijania zmiennych. Dosłowny tekst — $PATH nie zostanie rozwinięty. |
| >>> cmd | Isolated | Komenda w izolowanym subshell. Zmiany środowiska nie są propagowane do nadrzędnego procesu. |
| ( cmd ) | Grouped | Komenda w nawiasach — izolacja bez subshell (wynikowo jak >>> ale szybsza). |
@KATALOG="/tmp/projekt" @USER="admin" ! Komenda z podstawieniem zmiennych > mkdir -p $KATALOG > echo "Tworzę: $KATALOG dla $USER" ! Bez podstawiania — $KATALOG dosłownie >> echo 'Ścieżka: $KATALOG (nie rozwinięta)' ! Izolowany subshell — cd nie wpłynie na bieżący katalog >>> cd /tmp && ls -la && pwd ! Pipe — łańcuch komend > cat /etc/passwd | grep root | cut -d: -f1 ! Operator logiczny > ls -la $KATALOG || echo "Brak katalogu!" ! Komenda pogrupowana ( > cd /tmp && tar -czf archiwum.tar.gz . )
Przechwyt wyniku komendy
! Przechwyt do zmiennej lokalnej $ip="$(curl -s ifconfig.me)" $users="$(who | wc -l)" $free_mb="$(free -m | awk '/Mem:/{print $4}')" > echo "IP: $ip | Użytkownicy: $users | Wolna RAM: ${free_mb}MB"
Log / Out
v9: outlog wypisuje na stdout. out (v9) zwraca wartość z funkcji przez _HL_OUT.
$_HL_OUT jako wartość zwracaną z funkcji. Używane w połączeniu z $key = await .func.! Prosty log log "Uruchamiam skrypt..." log "Wersja: 2.0.0" log "Operacja zakończona." ! Dynamiczne wyjście przez echo (zmienne) $status="sukces" > echo "Status: $status" ! out — zwrócenie wartości z funkcji (v9) :pobierz_wersje def $v="$(cat /etc/version 2>/dev/null || echo 'unknown')" out $v done ! Przechwyt wartości z out $wersja = await .pobierz_wersje > echo "Wersja systemu: $wersja"
log wymaga cudzysłowów: log "tekst". Dla dynamicznych wartości ze zmiennymi używaj > echo "tekst $var". Instrukcja out jest no-op poza funkcją (VM ją ignoruje).Warunkowe: if / elif / else
Prefiksy ?, ?? i ?:. Warunek to dowolne wyrażenie bash test. Separator > (lub |>) oddziela warunek od komendy.
| Składnia | Odpowiednik bash | Opis |
|---|---|---|
| ? warunek > cmd | if warunek; then cmd; fi | Jeśli warunek true — wykonaj cmd |
| ?? warunek > cmd | elif warunek; then cmd | Kolejny warunek (elif) |
| ?: > cmd | else cmd; fi | Domyślna gałąź (else) |
$wiek=20 ! Podstawowy if ? $wiek -ge 18 > echo "Dorosły" ! If / elif / else (łańcuch) ? $wiek -lt 13 > echo "Dziecko" ?? $wiek -lt 18 > echo "Nastolatek" ?? $wiek -lt 65 > echo "Dorosły" ?: > echo "Senior" ! Sprawdzenie pliku ? -f /etc/nginx/nginx.conf > log "nginx jest zainstalowany" ?: > log "nginx NIE jest zainstalowany" ! Sprawdzenie katalogu ? -d /tmp/cache > log "Cache istnieje" ! Sprawdzenie zmiennej ? -n "$API_KEY" > log "API_KEY ustawiony" ?: > > echo "BŁĄD: API_KEY wymagany!" ! Złożone warunki bash ? [[ $wiek -gt 18 && "$USER" = "admin" ]] > echo "Admin dorosły"
Warunki z komendami
! Sprawdź czy komenda istnieje ? command -v docker > log "Docker dostępny" ! Sprawdź wynik komendy ? ping -c1 8.8.8.8 >/dev/null 2>&1 > log "Internet OK" ?: > log "Brak internetu!" ! Sprawdź kod wyjścia ? systemctl is-active --quiet nginx > log "nginx aktywny"
Match / Case
NOWE v9Dopasowanie wzorców. match $var |> otwiera blok, zakończony ramionami val > cmd. Kompiluje się do jednego shell case..esac (jeden syscall zamiast N).
$status="running" ! Blok match — otwieramy z |> match $status |> "running" > echo "Serwis działa" "stopped" > echo "Serwis zatrzymany" "error" > echo "Błąd serwisu!" "pending" > echo "Oczekiwanie..." _ > echo "Nieznany status: $status" ! Match z wartością numeryczną $kod="$(curl -so /dev/null -w '%{http_code}' https://example.com)" match $kod |> 200 > log "OK — serwer odpowiada" 404 > log "Nie znaleziono zasobu" 500 > log "Błąd serwera" 503 > log "Serwis niedostępny" _ > echo "HTTP $kod" ! Match z globbingiem match $LANG |> "pl*" > echo "Język polski" "en*" > echo "English" _ > echo "Inny język: $LANG"
val > cmd i buduje jeden string case..esac. N ramion = 1 syscall zamiast N. Znak _ to wildcard (domyślne ramię, odpowiada * w bash case).Pętla N razy
Składnia =N > cmd powtarza komendę dokładnie N razy. Prosta, bez zmiennej iteracyjnej.
! Prosta pętla 5 razy =5 > echo "Iteracja" ! Tworzenie plików =10 > touch /tmp/test_$(date +%N).tmp ! Ping N razy =3 > ping -c 1 8.8.8.8 | tail -1 ! Zmienna jako licznik @RETRY=5 =$RETRY > curl -s --retry 1 https://api.example.com/ping ! Funkcja wywoływana N razy =3 > .sprawdz_serwer
Pętla while
Powtarza komendę dopóki warunek jest spełniony. Warunek identyczny jak w ?.
! Czekaj na plik while ! -f /tmp/gotowy.lock > sleep 1 ! Czekaj aż serwer odpowie while ! curl -s http://localhost:8080/health >/dev/null > sleep 2 ! Monitorowanie procesu while pgrep -x nginx > sleep 5 ! Pętla z licznikiem $i=0 while [[ $i -lt 10 ]] > > i=$(( $i + 1 )) ! Czytanie linii z pliku while read line > echo "→ $line" < /etc/hosts
Pętla for
Iteruje po elementach listy, wzorcu glob lub wyniku komendy.
! Lista wartości for kolor in czerwony zielony niebieski > echo "Kolor: $kolor" ! Wzorzec glob (pliki) for plik in /var/log/*.log > echo "Log: $plik ($(wc -l < $plik) linii)" ! Wynik komendy for user in $(cat /etc/passwd | cut -d: -f1) > echo "User: $user" ! Zakres numeryczny for i in $(seq 1 10) > echo "Numer: $i" ! Argumenty skryptu ($@) for arg in $@ > echo "Argument: $arg" ! Hosty z pliku for host in $(cat hosts.txt) > ping -c1 $host >/dev/null && echo "$host OK" || echo "$host DOWN" ! Zmienne środowiskowe for serwis in nginx redis postgres > systemctl status $serwis --no-pager
Funkcje
Funkcje definiuje się przez :nazwa def ... done. Wywołanie: .nazwa [args]. Argumenty dostępne jako $1, $2... Funkcje ::nazwa def są oznaczone jako unsafe przez PLSA.
| Składnia | Opis |
|---|---|
| :nazwa def | Definicja zwykłej funkcji |
| ::nazwa def | Funkcja unsafe — PLSA oznacza jako niebezpieczną |
| done | Koniec definicji funkcji |
| .nazwa | Wywołanie funkcji |
| .nazwa arg1 arg2 | Wywołanie z argumentami (dostępne jako $1, $2...) |
| .klasa.metoda | Wywołanie metody klasy (z ;;Klasa def) |
! ── Zwykła funkcja ────────────────────────────── :powitaj def $imie="${1:-Świat}" > echo "Witaj, $imie!" done ! ── Funkcja z return przez out (v9) ───────────── :pobierz_ip def $ip="$(curl -s ifconfig.me)" out $ip done ! ── Funkcja unsafe (PLSA raportuje) ───────────── ::wyczysc_logi def > rm -f /var/log/app/*.log > journalctl --vacuum-size=100M log "Logi wyczyszczone" done ! ── Funkcja z warunkami i pętlą ────────────────── :sprawdz_serwisy def for s in nginx redis postgres > \ systemctl is-active --quiet $s && echo "✓ $s" || echo "✗ $s" done ! ── Wywołania ──────────────────────────────────── .powitaj .powitaj Jan $ip = await .pobierz_ip .sprawdz_serwisy ^.wyczysc_logi
Rekurencja i zaawansowane przykłady
! Funkcja z retry logic :retry_curl def $url="$1" $max="${2:-3}" $i=0 while [[ $i -lt $max ]] > \ curl -sf $url && out ok || > i=$(( $i + 1 )) done ! Funkcja generująca raport :raport_systemowy def > echo "=== Raport systemowy ===" > echo "Data: $(date)" > echo "Uptime: $(uptime -p)" > echo "RAM: $(free -h | awk '/Mem:/{print $3"/"$2}')" > echo "CPU: $(nproc) rdzeni" > echo "Dysk: $(df -h / | awk 'NR==2{print $5}')" done
Klasy
Klasy grupują funkcje w przestrzeń nazw. Definicja: ;;NazwaKlasy def ... done. Metody wywołuje się jako .NazwaKlasy.metoda.
! ── Klasa Serwer ──────────────────────────────── ;;Serwer def :start def $name="${1:-nginx}" > systemctl start $name log "Serwer $name uruchomiony" done :stop def > systemctl stop "${1:-nginx}" done :status def > systemctl status "${1:-nginx}" --no-pager done done ! ── Klasa Plik ────────────────────────────────── ;;Plik def :stworz def > touch "$1" > echo "Plik $1 stworzony" done :usun def > rm -f "$1" done done ! ── Wywołania metod ───────────────────────────── .Serwer.start nginx .Serwer.status nginx .Plik.stworz /tmp/test.txt
Try / Catch / Assert
v9: assertcmd zakończy się kodem != 0, wykonuje cmd2.! ── try / catch ────────────────────────────────── try curl -sf https://api.example.com/data catch log "Błąd połączenia z API" try cat /etc/config.txt catch echo "Brak pliku konfiguracyjnego, tworzę..." try ./deploy.sh catch > ./rollback.sh ! Try w pętli — obsługa błędów dla każdego elementu for host in srv1 srv2 srv3 > try ssh $host uptime catch echo "$host niedostępny" ! ── assert — walidacja v9 ──────────────────────── $config="/etc/myapp/config.yml" ! Assert z komunikatem assert -f $config "Plik konfiguracyjny nie istnieje: $config" assert -n "$DATABASE_URL" "DATABASE_URL jest wymagany" assert -d /var/log/myapp "Katalog logów nie istnieje" ! Assert bez komunikatu (domyślny) assert command -v docker assert [[ $UID -eq 0 ]] "Wymagane prawa roota" ! Assert z wyrażeniem złożonym assert [[ $MAX_CONN -gt 0 && $MAX_CONN -lt 1000 ]] "MAX_CONN poza zakresem (1-999)"
? warunek > exit 1. Idealne do walidacji parametrów na początku skryptów i funkcji.Pipe Chain
NOWE v9Łańcuchowe wywołania funkcji HL przez |>. Jeśli wszystkie kroki to funkcje HL, kompilator generuje sekwencję CallFunc (fast path, zero fork). Mieszane → shell pipe.
! ── All-HL pipe — szybka ścieżka (CallFunc) ────── .parsuj_dane |> .validuj |> .zapisz_do_bazy .pobierz_konfiguracje |> .scala_z_env |> .zastosuj ! ── Mieszany pipe — shell pipe ─────────────────── .generuj_liste_userow |> grep admin |> sort |> uniq ! ── Pipe z transformacją danych ────────────────── :wczytaj_json def > cat /tmp/dane.json done :filtruj_aktywne def > jq '.[] | select(.active == true)' done :formatuj_csv def > jq -r '.name + "," + .email' done .wczytaj_json |> .filtruj_aktywne |> .formatuj_csv
.func) i emituje sekwencję CallFunc zamiast uruchamiania shell pipe. All-HL pipe = zero fork/exec = ~10× szybszy.Spawn / Await
NOWE v9Asynchroniczne wykonanie zadań. spawn uruchamia w tle. await czeka na wynik. Możliwe przypisanie PID i przechwyt zwracanej wartości.
| Składnia | Opis |
|---|---|
| spawn cmd | Uruchom komendę w tle (fire & forget) |
| $key = spawn cmd | Uruchom w tle i przypisz PID do $key |
| await $pid | Czekaj na zakończenie procesu o danym PID |
| $key = await $pid | Czekaj i przypisz kod wyjścia do $key |
| $key = await .func | Wywołaj funkcję HL i przechwyt wartości z out |
! ── Fire and forget ───────────────────────────── spawn wget -q https://example.com/plik.zip -O /tmp/plik.zip spawn rsync -av /home/user/data/ backup:/mnt/backup/ ! ── Spawn z PID ───────────────────────────────── $pid_pobierania = spawn curl -s https://api.example.com/duzy-plik -O /tmp/out $pid_kompresji = spawn tar -czf /tmp/archiwum.tar.gz /home/user/ ! ── Await — czekaj na zakończenie ─────────────── await $pid_pobierania log "Pobieranie zakończone" ! ── Await z przechwytym kodu wyjścia ──────────── $wynik = await $pid_kompresji ? "$wynik" = "0" > log "Kompresja OK" ?: > echo "Błąd kompresji: kod $wynik" ! ── Await funkcji HL + out ─────────────────────── :oblicz_hash def $h="$(sha256sum $1 | cut -d' ' -f1)" out $h done $hash_pliku = await .oblicz_hash /tmp/plik.zip > echo "SHA256: $hash_pliku"
spawn, kontynuuj pracę, a na końcu await każdy PID. Pozwala efektywnie używać wielu rdzeni CPU bez blokowania programu.Enum
Wyliczenia — zbiór nazwanych stałych. Składnia: == NazwaEnum [wariant1, wariant2, ...]. PLSA weryfikuje użycie poprawnych wartości.
! Definicje enum == Status [running, stopped, error, pending, unknown] == LogLevel [debug, info, warn, error, fatal] == Protokol [http, https, ftp, ssh, smtp] == Srodowisko [production, staging, testing, development] ! Użycie w warunkach ? "$status" = "running" > log "System aktywny" ? "$env" = "production" > log "UWAGA: produkcja!" ! Enum z match (v9) match $status |> "running" > echo "✓ działa" "error" > echo "✗ błąd" _ > echo "? nieznany"
Struct
Struktury danych z polami i typami. Składnia: struct NazwaStruct [pole:typ, ...]. Typy: str, int, bool, float, lub nazwa Enum.
! Definicje struct struct Uzytkownik [imie:str, wiek:int, aktywny:bool, email:str] struct Serwer [host:str, port:int, protokol:Protokol, ssl:bool] struct KonfiguracjaDB [host:str, port:int, nazwa:str, user:str, haslo:str] ! Instancja (przypisanie pól) $db=KonfiguracjaDB[host="localhost", port=5432, nazwa="myapp", user="admin", haslo="$DB_PASS"] ! Użycie w funkcjach :polacz_z_db def > psql -h $db.host -p $db.port -U $db.user $db.nazwa done
Biblioteki
Import przez #<typ/nazwa:wersja>. Biblioteki są instalowane przez bit lub dostępne lokalnie w ~/.hackeros/hacker-lang/libs/.
libs/core/. Podstawowe I/O, HTTP, JSON, kryptografia..so z libs/bytes/. Instalacja: bytes install <nazwa>..a z libs/.vira/. Dla zaawansowanych narzędzi niskopoziomowych.~/.hackeros/hacker-lang/libs/.vira/. Współdzielone przez community.! Lokalna biblioteka source #<source/utils> #<source/logger> ! Core z wersją semver #<core/io:2.1.0> #<core/http:1.3> #<core/json:1.0> #<core/crypto:2.0> ! Skompilowane (bytes) #<bytes/openssl> #<bytes/sqlite3> ! GitHub #<github/hackeros/hl-stdlib:0.9.2> ! Po imporcie używamy funkcji z biblioteki .http.get https://api.example.com .json.parse
Import
v9: namespaceImportuje plik .hl lub zasób. << "ścieżka" — prosty import. << "ścieżka" in ns — import z przestrzenią nazw (v9).
! Import bezpośredni — kod wstawiony inline << "config/app.conf" << "/etc/myapp/settings.hl" ! Import z namespace (v9) — funkcje dostępne jako .ns.nazwa << "lib/helpers.hl" in helpers ! Po imporcie z namespace .helpers.formatuj_date .helpers.log_error "coś poszło nie tak"
Zależności systemowe
// narzędzie1 narzędzie2 deklaruje wymagane narzędzia. PLSA sprawdza ich obecność i raportuje brakujące przed uruchomieniem.
! Kilka zależności w jednej linii // curl jq git ! Lub osobno // docker // ffmpeg // openssl ! PLSA sprawdzi: command -v curl && command -v jq && ... > curl -s https://api.example.com | jq '.data'
Pluginy
Zewnętrzne pliki (.hl lub binarne) z ~/.hackeros/hacker-lang/plugins/. Uruchomienie: \\nazwa [args]. Instalacja: bit install plugin <nazwa>.
! Plugin bez argumentów \\backup ! Plugin z argumentami \\kompresuj /home/user/dokumenty --level=9 \\deploy staging --tag=v1.2.3 ! Plugin z sudo ^\\instaluj curl git vim neovim ! Plugin asynchronicznie (v9) spawn .backup $pid_sync = spawn .sync_pliki /home/user
Extern — linkowanie zewnętrzne
-- ścieżka — dynamiczne. -- static ścieżka — statyczne. Deklaruje zewnętrzne biblioteki C/C++ do integracji.
! Dynamiczne linkowanie -- /usr/lib/libssl.so -- /usr/lib/x86_64-linux-gnu/libcurl.so.4 ! Statyczne linkowanie -- static /usr/local/lib/libsodium.a -- static ~/.hackeros/hacker-lang/lib/libgc.a
Sudo (^)
Prefiks ^ przed dowolną instrukcją. PLSA zbiera listę ostrzeżeń bezpieczeństwa dla wszystkich linii z ^.
! Komenda z sudo ^> apt-get update && apt-get upgrade -y ^> systemctl restart nginx ! Funkcja z sudo ^.wyczysc_system ! Plugin z sudo ^\\instaluj curl git ! Pętla z sudo ^=3 > chown root:root /etc/myapp/config.yml
^ jako potencjalnie niebezpieczne i generuje raport bezpieczeństwa. Używaj wyłącznie gdy to konieczne. Nigdy nie uruchamiaj nieznanych skryptów z ^ bez inspekcji.Lock / Unlock
Blokowanie i odblokowywanie zmiennych. lock czyni zmienną niemodyfikowalną w ramach sesji.
! Zablokuj zmienną — nie można nadpisać lock $WERSJA = "1.0.0" lock $MAX_POLACZEN = 100 lock $API_URL = "https://api.example.com" ! Odblokuj (jeśli potrzebna zmiana) unlock $WERSJA ! Lock w połączeniu z assert (v9) assert -n "$API_URL" "API_URL wymagany przed lockiem" lock $API_URL = "$API_URL"
Background (&)
Uruchamia komendę w tle. Starsza składnia — w v9 preferuj spawn/await dla kontrolowanej asynchroniczności z PID.
! Uruchom serwer w tle & python3 -m http.server 8080 & redis-server --port 6380 ! Równoległe pobieranie & wget -q https://example.com/plik1.zip & wget -q https://example.com/plik2.zip & wget -q https://example.com/plik3.zip ! Poczekaj na wszystkie procesy tła > wait log "Wszystko pobrane" ! V9 alternatywa (kontrolowana): $p1 = spawn wget -q https://example.com/plik1.zip $p2 = spawn wget -q https://example.com/plik2.zip await $p1 await $p2
Raw block [ ... ]
Surowy blok — zawartość przekazywana bezpośrednio do bash bez parsowania przez hacker-lang. Przydatne do heredoc, inline skryptów i złożonych potoków.
! Surowy blok bash [ #!/bin/bash for i in $(seq 1 5); do echo "Liczba: $i" done # Złożone przetwarzanie find /var/log -name "*.log" -mtime -7 \ | xargs grep -l "ERROR" \ | sort -u \ | tee /tmp/bledy_lista.txt ] ! Raw do generowania pliku konfiguracyjnego [ cat > /etc/myapp/config.yml <<EOF server: host: localhost port: 8080 debug: false database: url: $DATABASE_URL EOF ]
Przykład: Hello World
! hello.hl — pierwszy program w hacker-lang %VERSION="1.0.0" @NAZWA="${1:-Świat}" :powitaj def > echo "Witaj, $NAZWA!" log "Program działa poprawnie." > echo "Wersja: $VERSION" done .powitaj end 0 ! Uruchomienie: hl-runtime hello.hl Jan
Przykład: Skrypt backupu
! backup.hl — kompletny skrypt backupu z v9 // tar rsync %MAX_BACKUP_MB=5120 @SRC_DIR="/home/user/dokumenty" @BACKUP_DIR="/mnt/backup" @REMOTE="user@backup-server:/mnt/backup" ! ── Walidacja środowiska (v9 assert) ──────────── assert -d $SRC_DIR "Katalog źródłowy nie istnieje: $SRC_DIR" assert -d $BACKUP_DIR "Katalog backupu nie istnieje: $BACKUP_DIR" :sprawdz_miejsce def $wolne="$(df -m $BACKUP_DIR | awk 'NR==2{print $4}')" assert [[ $wolne -gt $MAX_BACKUP_MB ]] "Za mało miejsca: ${wolne}MB < ${MAX_BACKUP_MB}MB" > echo "Wolne miejsce: ${wolne}MB OK" done :zrob_backup def $data="$(date +%Y%m%d_%H%M%S)" $plik="$BACKUP_DIR/backup_$data.tar.gz" try tar -czf $plik $SRC_DIR catch > log "Backup nieudany!" > echo "Zapisano: $plik ($(du -sh $plik | cut -f1))" out $plik done :sync_zdalny def $plik="$1" log "Synchronizuję zdalnie..." try rsync -avz $plik $REMOTE catch log "Sync nieudany (brak sieci?)" done ! ── Główna logika ─────────────────────────────── log "=== Backup start ===" .sprawdz_miejsce $plik_backupu = await .zrob_backup ? -n "$REMOTE" > .sync_zdalny $plik_backupu > du -sh $BACKUP_DIR log "=== Backup zakończony ===" end 0
Przykład: REST API klient
! api-klient.hl — REST API z obsługą błędów // curl jq #<core/http:1.3> %API_BASE="https://jsonplaceholder.typicode.com" @TOKEN="${API_TOKEN:-demo}" ! Walidacja środowiska assert command -v jq "jq jest wymagany" assert command -v curl "curl jest wymagany" :api_get def $endpoint="$1" $resp="$(curl -sf -H "Authorization: Bearer $TOKEN" $API_BASE$endpoint)" out $resp done :api_post def $endpoint="$1" $data="$2" $resp="$(curl -sf -X POST -H 'Content-Type: application/json' \ -H "Authorization: Bearer $TOKEN" \ -d "$data" $API_BASE$endpoint)" out $resp done ! Pobierz listę postów $posty = await .api_get /posts > echo $posty | jq '.[0:3] | .[] | {id, title}' ! Sprawdź kod HTTP i obsłuż match (v9) $kod="$(curl -so /dev/null -w '%{http_code}' $API_BASE/posts)" match $kod |> 200 > log "API OK" 401 > log "Brak autoryzacji — sprawdź TOKEN" 429 > log "Rate limit — poczekaj chwilę" 503 > log "API niedostępne" _ > echo "Nieznany kod: $kod" end 0
Przykład: Async tasks (v9)
! async-deploy.hl — równoległe wdrożenie na serwery // ssh rsync %APP_DIR="/var/www/myapp" %VERSION="$(git describe --tags --abbrev=0)" assert command -v git "git wymagany" assert -d $APP_DIR "Katalog aplikacji nie istnieje" assert -n "$VERSION" "Brak tagu git" :deploy_na def $host="$1" log "Deploy na $host..." try rsync -avz --delete $APP_DIR/ $host:$APP_DIR/ \ catch echo "BŁĄD: deploy na $host nieudany" try ssh $host "systemctl restart myapp" \ catch echo "BŁĄD: restart na $host nieudany" out "$host:ok" done ! ── Równoległe wdrożenie na 3 serwery ─────────── log "Wdrażam $VERSION na wszystkie serwery..." $pid1 = spawn .deploy_na web1.example.com $pid2 = spawn .deploy_na web2.example.com $pid3 = spawn .deploy_na web3.example.com ! Czekaj na wszystkie $r1 = await $pid1 $r2 = await $pid2 $r3 = await $pid3 > echo "web1: $r1 | web2: $r2 | web3: $r3" log "Wdrożenie zakończone" end 0
Przykład: System Monitor
! monitor.hl — pełny monitor systemu // awk free df uptime %CPU_WARN=80 %MEM_WARN=90 %DISK_WARN=85 :check_cpu def $cpu="$(top -bn1 | grep 'Cpu(s)' | awk '{print int($2)}')" match "$(( $cpu >= $CPU_WARN ))" |> "1" > echo "⚠ CPU: ${cpu}% (wysoki!)" _ > echo "✓ CPU: ${cpu}%" done :check_memory def $total="$(free -m | awk '/Mem:/{print $2}')" $used="$(free -m | awk '/Mem:/{print $3}')" $proc=$(( $used * 100 / $total )) ? [[ $proc -ge $MEM_WARN ]] > echo "⚠ RAM: ${proc}% (${used}/${total}MB) — wysoki!" ?: > echo "✓ RAM: ${proc}% (${used}/${total}MB)" done :check_disk def for mp in / /home /var > \ $proc="$(df $mp 2>/dev/null | awk 'NR==2{print int($5)}')" ? [[ $proc -ge $DISK_WARN ]] > echo "⚠ Dysk $mp: ${proc}% (pełny!)" ?: > echo "✓ Dysk $mp: ${proc}%" done ! ── Uruchom wszystkie sprawdzenia równolegle ──── > echo "=== Monitor systemowy — $(date '+%H:%M:%S') ===" > echo "Uptime: $(uptime -p)" > echo "---" $p1 = spawn .check_cpu $p2 = spawn .check_memory $p3 = spawn .check_disk await $p1 await $p2 await $p3 end 0
Cheat Sheet
Kompletna ściągawka składni Hacker Lang v9.
Zmienne i stałe
| Składnia | Opis |
|---|---|
| @VAR=val | Zmienna env (globalna) |
| $key=val | Zmienna lokalna |
| %KEY=val | Stała (v9) |
| ~$key=val | Zmienna raw (bez $-sub) |
Komendy
| > cmd | Z podstawianiem zmiennych |
| >> cmd | Bez podstawiania |
| >>> cmd | Izolowany subshell |
| ( cmd ) | Pogrupowane |
Sterowanie
| ? c > cmd | If |
| ?? c > cmd | Elif |
| ?: > cmd | Else |
| match $v |> | Match block (v9) |
| =N > cmd | Pętla N razy |
| while c > cmd | Pętla while |
| for v in e > cmd | Pętla for |
Funkcje i klasy
| :nazwa def...done | Definicja funkcji |
| ::nazwa def...done | Funkcja unsafe |
| ;;Klasa def...done | Definicja klasy |
| .nazwa [args] | Wywołanie |
| .K.metoda | Metoda klasy |
| out val | Zwróć wartość (v9) |
Async (v9)
| spawn cmd | Uruchom w tle |
| $k = spawn cmd | Spawn + PID |
| await $pid | Czekaj |
| $k = await $pid | Await + kod wyjścia |
| $k = await .f | Await + out |
Błędy i walidacja
| try c catch c2 | Obsługa błędu |
| assert cond [msg] | Asercja (v9) |
| .a |> .b |> .c | Pipe chain (v9) |
Pełna lista prefiksów i słów kluczowych
| Składnia | Opis |
|---|---|
| ! tekst | Komentarz liniowy |
| !! | Przełącz komentarz blokowy |
| == Enum [a,b,c] | Definicja enum |
| struct S [f:t] | Definicja struktury |
| #<typ/nazwa:ver> | Import biblioteki |
| // dep1 dep2 | Zależności systemowe |
| \\ plugin [args] | Uruchom plugin |
| -- ścieżka | Extern dynamiczny |
| -- static ścieżka | Extern statyczny |
| ^ prefix | Sudo (przed instrukcją) |
| lock $k = val | Zablokuj zmienną |
| unlock $k | Odblokuj zmienną |
| & cmd | Uruchom w tle (stara składnia) |
| << "plik" [in ns] | Import zasobu (v9: namespace) |
| [ ... ] | Raw block (bez parsowania) |
| log "tekst" | Wypisz string |
| end [N] | Zakończ program |
hl run skrypt.hl — uruchomhl run skrypt.hl --verbose — z disassemblyhl check skrypt.hl — tylko analizahl compile skrypt.hl - skompiluj program hl do statycznej binarkibit install <lib> — zainstaluj bibliotekębit install plugin <plugin> — zainstaluj plugin