volangprogramowaniejęzykautomatyzacja

# Język Volang

Witamy w dokumentacji języka Volang, autorskiego języka programowania Voldeno. Służy on jako podstawowe narzędzie do implementacji logiki bloków w naszym ekosystemie inteligentnego domu.

# Wprowadzenie

Volang to wyspecjalizowany język programowania opracowany przez Voldeno, zaprojektowany specjalnie do implementacji logiki bloków w ekosystemie inteligentnego domu. Łączy możliwości sprzętowe z automatyzacją wysokiego poziomu, umożliwiając programistom tworzenie zaawansowanych scenariuszy sterowania w sposób wydajny i bezpieczny.

Głównym celem Volang jest definiowanie zachowania Bloków. W systemie Voldeno blok reprezentuje autonomiczną jednostkę funkcjonalną (np. sterownik rolet, termostat lub licznik energii). Volang pozwala programistom określić, jak te bloki reagują na sygnały wejściowe, przetwarzają stan wewnętrzny i wyzwalają akcje na podstawie zdarzeń.

# Architektura: Model kompilowany

W przeciwieństwie do prostych języków skryptowych interpretowanych bezpośrednio z tekstu, Volang wykorzystuje architekturę Maszyny Wirtualnej (VM). Proces wykonania składa się z dwóch odrębnych etapów:

  1. Kompilacja: Kod źródłowy napisany przez programistę jest przetwarzany przez kompilator Volang. Ten krok weryfikuje składnię, typy danych i integralność logiczną, przekształcając kod w zoptymalizowany format binarny znany jako bytecode.
  2. Wykonanie: Wynikowy bytecode jest ładowany do Maszyny Wirtualnej Volang (Volang VM) — dedykowanego środowiska uruchomieniowego działającego na kontrolerach Voldeno. VM odpowiada za interpretację instrukcji bytecode i ich bezpieczne wykonanie na sprzęcie fizycznym.

# Dlaczego Volang VM?

Przyjęcie architektury maszyny wirtualnej oferuje znaczące korzyści dla środowisk inteligentnego domu, unifikuje przepływ pracy programistycznej i rozszerza możliwości sprzętu:

  • Bezpieczeństwo (Sandboxing): Kod użytkownika działa w izolowanym środowisku, oddzielonym od podstawowego systemu operacyjnego. Błąd wykonania (np. dzielenie przez zero) zatrzyma tylko konkretny skrypt w VM, zapewniając nienaruszalność ogólnej stabilności kontrolera.
  • Wydajność: Wykonywanie kompaktowego binarnego bytecode jest znacznie szybsze i bardziej efektywne pod względem zasobów niż parsowanie plików tekstowych w czasie wykonania, co jest kluczowe dla systemów wbudowanych i mikrokontrolerów.
  • Przenośność: Logika napisana w Volang jest niezależna od sprzętu. Może być wykonywana na dowolnym urządzeniu zdolnym do uruchomienia Volang VM, niezależnie od podstawowej architektury procesora.
  • Identyczna symulacja: Ponieważ Volang VM działa spójnie na różnych platformach, dokładnie ta sama logika bloku może być wykonana w Voldeno Studio. Pozwala to programistom testować i debugować kod w środowisku desktopowym z gwarancją, że zachowanie będzie identyczne z rzeczywistym systemem produkcyjnym.
  • Rozproszone wykonanie: Wydajność VM pozwala na uruchamianie jej nie tylko na centralnym Voldeno Hub, ale także na modułach rozszerzeń peryferyjnych. Ta możliwość umożliwia prawdziwie rozproszoną logikę, gdzie złożone przetwarzanie może odbywać się lokalnie na urządzeniu (na brzegu sieci) bez ograniczenia do podstawowego raportowania zdarzeń.

# Konwencje leksykalne

# Słowa kluczowe

Następujące słowa są zarezerwowane w Volang i nie mogą być używane jako nazwy zmiennych lub funkcji. Tworzą one strukturalną podstawę języka.

and        break        else        
extern     false        fn           
if         or           shl
shr        return       true       
while      xor

# Literały

W Volang literał to notacja reprezentująca stałą wartość bezpośrednio w kodzie źródłowym. To surowe wartości danych, które przypisujesz do zmiennych lub przekazujesz do funkcji. Volang obsługuje określone formaty dla literałów logicznych, łańcuchowych, całkowitych i zmiennoprzecinkowych.

# Literały logiczne (Boolean)

Używane do reprezentowania stanów logicznych. Istnieją dokładnie dwa literały logiczne:

  • true: Reprezentuje stan pozytywny lub aktywny (Włączony).
  • false: Reprezentuje stan negatywny lub nieaktywny (Wyłączony).

# Literały całkowite (Integer)

Literały całkowite reprezentują liczby całkowite. Volang obsługuje dwie notacje:

  • Dziesiętna (Baza-10): Standardowa reprezentacja numeryczna używająca cyfr 0-9. Liczby ujemne są poprzedzone znakiem minus -. Wartości muszą się mieścić w przedziale od -9223372036854775808 do 9223372036854775807.
  • Szesnastkowa (Baza-16): Często używana dla kodów kolorów, masek bitowych lub adresów sprzętowych. Te literały muszą zaczynać się od przedrostka 0x po którym następują cyfry 0-9 i litery A-F (wielkość liter nie ma znaczenia).

# Literały zmiennoprzecinkowe (Float)

Literały zmiennoprzecinkowe reprezentują liczby z częścią ułamkową.

  • Składnia: Zapisywane są w notacji dziesiętnej z kropką . jako separatorem dziesiętnym.
  • Wymaganie: Prawidłowy literał float zazwyczaj wymaga co najmniej jednej cyfry przed lub po kropce dziesiętnej (np. 0.5, 10.0, 23.34).

# Literały tekstowe (String)

Literały tekstowe reprezentują sekwencje znaków i są używane do wiadomości, identyfikatorów lub etykiet.

  • Składnia: Tekst musi być ujęty w podwójne cudzysłowy ".
  • Obsługa wieloliniowa: Literał łańcuchowy w Volang może rozciągać się na wiele linii. Znaki nowej linii wewnątrz cudzysłowów są zachowywane.

# Surowe łańcuchy (Raw Strings)

Surowe łańcuchy są używane do reprezentowania tekstu dokładnie tak, jak został napisany, ignorując znaki specjalne lub formatowanie.

  • Składnia: Surowe łańcuchy muszą być ujęte w potrójne podwójne cudzysłowy """.
  • Użycie: Wszystko wewnątrz potrójnych cudzysłowów jest traktowane jako tekst dosłowny. Jest to szczególnie przydatne do przechowywania bloków kodu, złożonych wzorców regex lub wstępnie sformatowanej dokumentacji.
  • Zachowanie: Podobnie jak standardowe łańcuchy wieloliniowe, wszystkie wcięcia i podziały linii są zachowywane dokładnie tak, jak pojawiają się między ogranicznikami """.

Przykłady:

// --- Literały logiczne ---
swiatlo_wlaczone = true
drzwi_zamkniete = false

// --- Literały całkowite (Dziesiętne) ---
licznik = 10
przesuniecie_ujemne = -5

// --- Literały całkowite (Szesnastkowe) ---
maska_statusu = 0xFF       // Dziesiętnie 255
kolor_czerwony = 0xFF0000  // Kod koloru

// --- Literały zmiennoprzecinkowe ---
temperatura = 23.34
wspolczynnik_kalibracji = 0.95
napiecie = 12.0            // .0 wskazuje, że to Float, nie Integer

// --- Literały łańcuchowe ---
nazwa_urzadzenia = "Termostat salon"

// Łańcuch wieloliniowy (zachowuje formatowanie)
komunikat_powiadomienia = "
Ostrzeżenie: Wysoka temperatura!
Akcja: Chłodzenie aktywowane
Czas: 12:00
"

// --- Surowy literał łańcuchowy ---
configJson = """
{
    "status": "sukces",
    "katalog": "C:\users\volang\app",
    "wzorzec": "\b[A-Z0-9._%+-]+",
    "opis": "Nie trzeba escapować backslashy ani "cudzysłowów" tutaj!"
}
"""

# Wartości i typy

Volang działa na dynamicznym systemie typów, oferując elastyczne podejście do zarządzania danymi. W Volang zmienne funkcjonują jako generyczne kontenery, a nie ściśle typowane magazyny. W związku z tym nie ma potrzeby jawnego deklarowania typów (takich jak int lub float) w kodzie. Informacja o typie jest nieodłączna od samej wartości, nie od przypisanej do niej zmiennej.

# Wartości pierwszej klasy

Wszystkie wartości w Volang są wartościami pierwszej klasy. Oznacza to, że każda wartość, niezależnie od typu, może być:

  • Przechowywana w zmiennych.
  • Przekazywana jako argumenty do funkcji.
  • Zwracana jako wyniki z funkcji.

# Spójność typów (Ścisłe typowanie)

Chociaż Volang nie wymaga deklaracji typów, wymusza stabilność typów. Gdy zmienna zostanie przypisana wartość określonego typu (np. Integer), staje się związana z tym typem. Nie można następnie przypisać wartości innego typu (np. String) do tej samej zmiennej. Ten mechanizm zapobiega typowym błędom wykonania i zapewnia przewidywalne zachowanie kontrolera.

# Kategorie wartości

Volang rozróżnia cztery podstawowe rodzaje wartości:

# 1. Numeryczne (Integer i Float)

Używane do obliczeń matematycznych, odczytów czujników i liczników.

  • Integer: Liczby całkowite bez części ułamkowej (np. 0, 42, -15).
  • Float: Liczby zmiennoprzecinkowe reprezentujące wartości ułamkowe (np. 3.14, 21.5, -0.001).

# 2. Tekstowe (String)

Używane do komunikatów statusu, logów, nazw i przetwarzania tekstu. Łańcuchy to sekwencje znaków ujęte w podwójne cudzysłowy ".

  • Obsługa wieloliniowa: Volang obsługuje łańcuchy wieloliniowe. Możesz nacisnąć Enter wewnątrz cudzysłowów, aby utworzyć blok tekstu rozciągający się na kilka linii.

# 3. Logiczne (Boolean)

Wartości logiczne reprezentują wartości prawdy i są kluczowe dla logiki decyzyjnej (if, while).

  • Wartości: true lub false.

# 4. Nieprzezroczyste (Opaque)

Wartości nieprzezroczyste reprezentują złożone struktury danych, których wewnętrzna implementacja jest zarządzana przez Volang VM. Użytkownik korzysta z nich za pośrednictwem dedykowanych funkcji Biblioteki Standardowej, a nie bezpośrednich operatorów składniowych. Przykłady typów nieprzezroczystych to m.in.:

  • Array (Tablica): Uporządkowana, indeksowana kolekcja wartości.
  • Map (Mapa): Kolekcja par klucz-wartość, gdzie każdy klucz jest unikalny.

To tylko niektóre z dostępnych typów nieprzezroczystych — Biblioteka Standardowa może udostępniać kolejne. Wartości nieprzezroczyste podlegają tym samym regułom pierwszej klasy co inne typy — mogą być przechowywane w zmiennych, przekazywane jako argumenty i zwracane z funkcji. Nie mogą jednak być używane ze standardowymi operatorami arytmetycznymi ani logicznymi.

Przykład:

// 1. Dynamiczne typowanie
status = 25.5    

// 2. Łańcuchy wieloliniowe
info_konfiguracji = "Urządzenie: Termostat
    Lokalizacja: Salon
    Firmware: v1.2"

// 3. Przekazywanie wartości
fn logujStatus(wiadomosc) {
    print(wiadomosc)
}

logujStatus(info_konfiguracji)

# Zmienne

Volang stosuje uproszczone podejście do zarządzania zmiennymi. Nie ma słów kluczowych deklaracji (takich jak var, let lub int). Zmienna jest tworzona w momencie przypisania wartości do nazwy. Miejsce, w którym definiujesz zmienną, określa jej zakres (widoczność) w całym skrypcie.

# Tworzenie zmiennych

Aby zdefiniować zmienną, po prostu użyj operatora przypisania =. Typ danych zmiennej jest wnioskowany z przypisanej wartości i staje się stały na czas życia tej zmiennej.

Składnia:

nazwa_zmiennej = wartosc

# Zakres zmiennych

Zakres określa, gdzie zmienna może być dostępna w kodzie. Volang rozróżnia dwa typy zakresu:

# Zmienne globalne

Zmienne zdefiniowane na najwyższym poziomie skryptu (poza jakąkolwiek funkcją lub blokiem sterującym) są Globalne.

  • Widoczność: Są dostępne z dowolnego miejsca w skrypcie, ale nie wewnątrz funkcji. Aby użyć wartości globalnej w funkcji, przekaż ją jako argument.
  • Zastosowanie: Idealne do przechowywania ogólnego stanu urządzenia, takiego jak temperatura_docelowa, tryb_systemu lub status_alarmu.

# Zmienne lokalne

Zmienne zdefiniowane wewnątrz funkcji (fn) lub bloku sterującego są Lokalne.

  • Widoczność: Istnieją tylko w bloku, w którym zostały utworzone. Są niszczone, gdy wykonanie opuszcza ten blok.
  • Zastosowanie: Używane do tymczasowych obliczeń, liczników pętli lub pośrednich kroków logicznych.

Przykład:

// --- Zmienne globalne ---
status_systemu = "BEZCZYNNY"
nastawiona = 21.5

// Zmienne globalne NIE SĄ dostępne wewnątrz funkcji.
// Przekaż je jako argumenty:
fn sprawdzTemperature(aktualna_temp, cel) {
    // --- Zmienna lokalna ---
    // 'roznica' istnieje tylko wewnątrz tej funkcji
    roznica = aktualna_temp - cel
    
    if roznica > 1.0 {
        return "Wymagane chłodzenie"
    }
    
    return "Stabilna"
}

// Przekaż globalną 'nastawiona' jako argument
wynik = sprawdzTemperature(22.8, nastawiona)

// 'roznica' nie jest tutaj dostępna

# Komentarze

Komentarze to fragmenty kodu ignorowane przez kompilator Volang. Służą do wyjaśniania logiki, pozostawiania notatek dla innych programistów lub tymczasowego wyłączania określonych części kodu podczas testowania.

# Komentarze jednoliniowe

Komentarze jednoliniowe zaczynają się od dwóch ukośników //. Cały tekst następujący po tych znakach do końca linii jest traktowany jako komentarz.

# Komentarze wieloliniowe

Komentarze wieloliniowe (blokowe) zaczynają się od /* i kończą na */. Wszystko między tymi znacznikami jest ignorowane, niezależnie od liczby linii.

Przykład:

// To jest komentarz jednoliniowy
tempDocelowa = 21.5 // Komentarz na końcu linii

/*
   To jest komentarz wieloliniowy.
   Przydatny do opisywania złożonej logiki
   lub nagłówków bloków.
*/

/* staraLogika = 10
if (staraLogika > 5) {
   // Ten kod jest wyłączony
}
*/

# Instrukcje

Volang jest zaprojektowany, aby minimalizować szum wizualny i maksymalizować czytelność. W przeciwieństwie do języków takich jak C++ czy Java, Volang nie używa średników (;) do oznaczania końca instrukcji.

Znak nowej linii (naciśnięcie Enter) służy jako definitywny terminator instrukcji. Kompilator interpretuje koniec linii jako zakończenie bieżącego polecenia.

# Przypisania

Operatory przypisania służą do przechowywania wartości w zmiennej. Volang obsługuje standardowy podstawowy operator przypisania oraz złożone operatory przypisania.

# Podstawowe przypisanie

Operator = przypisuje wartość z prawej strony do zmiennej po lewej stronie.

temp_docelowa = 21.0
licznik_zdarzen = 0

# Złożone operatory przypisania

Złożone operatory wykonują operację na bieżącej wartości zmiennej, a następnie aktualizują ją nowym wynikiem.

OperatorOpis
+=Dodaj i przypisz
-=Odejmij i przypisz
*=Pomnóż i przypisz
/=Podziel i przypisz

Kluczowe zachowania:

  1. Wymaganie inicjalizacji: Dla złożonych operatorów zmienna po lewej stronie musi już istnieć.
  2. Promocja typów: Złożone przypisanie podlega tym samym regułom promocji typów co standardowa arytmetyka.

Przykłady:

// Inkrementacja licznika
licznik_zdarzen += 1

// Zmniejszenie nastawy
temp_docelowa -= 0.5

// Skalowanie jasności do 80%
jasnosc = 100
jasnosc *= 0.8  // Wynik: 80.0

// Akumulacja energii
calkowita_energia_kwh = 0.0
biezace_zuzycie = 1.5
calkowita_energia_kwh += biezace_zuzycie

# Sterowanie przepływem

Instrukcja if jest podstawową strukturą decyzyjną w Volang. Wyrażenie warunkowe musi zwracać wartość logiczną (true lub false). Wartości innych typów (takie jak liczby całkowite, zmiennoprzecinkowe czy łańcuchy tekstowe) nie są niejawnie konwertowane — użycie ich jako warunku spowoduje błąd kompilacji.

# Podstawowy if

if (warunek) {
    // Kod do wykonania jeśli warunek jest prawdziwy
}

# if z else

if (warunek) {
    // Kod do wykonania jeśli warunek jest prawdziwy
} else {
    // Kod do wykonania jeśli warunek jest fałszywy
}

# Łańcuchowe warunki (else if)

if (warunek_1) {
    // Wykonuje się jeśli warunek_1 jest prawdziwy
} else if (warunek_2) {
    // Wykonuje się jeśli warunek_1 jest fałszywy I warunek_2 jest prawdziwy
} else {
    // Wykonuje się jeśli wszystkie powyższe warunki są fałszywe
}

Przykład - Logika termostatu:

aktualna_temp = 19.0
temp_docelowa = 21.0
histereza = 0.5

if (aktualna_temp < (temp_docelowa - histereza)) {
    // Za zimno -> Włącz ogrzewanie
    ustawOgrzewanie(true)
    
} else if (aktualna_temp > (temp_docelowa + histereza)) {
    // Za gorąco -> Włącz chłodzenie
    ustawChlodzenie(true)
    
} else {
    // Temperatura w optymalnym zakresie
    ustawOgrzewanie(false)
    ustawChlodzenie(false)
}

# Pętle

Volang obsługuje jedną konstrukcję pętli: pętlę while. W języku nie ma pętli for ani do-while. Podobnie jak w przypadku if, wyrażenie warunkowe musi zwracać wartość logiczną (true lub false).

Składnia:

while (warunek) {
    // Kod do powtarzalnego wykonania
}

Volang obsługuje słowo kluczowe break wewnątrz pętli. Gdy napotkane zostanie break, pętla jest natychmiast zakończona.

Warning

W systemach wbudowanych i kontrolerach inteligentnego domu nieskończone pętle mogą być niebezpieczne. Volang VM monitoruje czas wykonania, ale to twoja odpowiedzialność, aby upewnić się, że warunek pętli ostatecznie stanie się false lub że zostanie osiągnięta instrukcja break.

Przykłady:

// Podstawowy licznik
licznik = 5

while (licznik > 0) {
    logujWartosc(licznik)
    licznik -= 1
}

// Oczekiwanie z limitem czasu (używając break)
proby = 0
max_ponowien = 10
sukces = false

while (proby < max_ponowien) {
    if (sprawdzPolaczenie()) {
        sukces = true
        break
    }
    proby += 1
}

if (sukces) {
    rozpocznijProces()
}

# Funkcje

Funkcje to wielokrotnego użytku bloki kodu zaprojektowane do wykonywania określonego zadania. W Volang funkcje definiuje się przy użyciu słowa kluczowego fn.

Składnia:

fn nazwaFunkcji(argument1, argument2) {
    // Kod do wykonania
}

Kluczowe zasady:

  1. Argumenty: Funkcja może przyjmować wiele argumentów (oddzielonych przecinkami) lub nie przyjmować żadnych.
  2. Wartości zwracane: Użyj return, aby odesłać wartość. Jeśli pominięty, funkcja nie zwraca nic (void).
  3. Ograniczenia nazewnictwa: Nazwy funkcji muszą być różne od nazw funkcji Biblioteki Standardowej.
  4. Zakres: Zmienne zdefiniowane wewnątrz funkcji są lokalne dla tej funkcji.
  5. Brak dostępu do globali: Zmienne globalne nie są dostępne wewnątrz funkcji. Wszelkie zewnętrzne dane potrzebne funkcji muszą być przekazane jako argumenty.

Przykład:

fn obliczSrednia(a, b, c) {
    suma = a + b + c
    return suma / 3
}

srednia = obliczSrednia(20.5, 21.0, 19.5)

# Wyrażenia

# Binarne operatory arytmetyczne

OperatorOpis
+Dodawanie
-Odejmowanie
*Mnożenie
/Dzielenie
%Modulo

Priorytet: Mnożenie, Dzielenie i Modulo są obliczane przed Dodawaniem i Odejmowaniem.

Przykłady:

// Kalibracja czujnika
surowa_wartosc = 50
wspolczynnik_skali = 1.2
przesuniecie = 5.0
skalibrowana_wartosc = surowa_wartosc * wspolczynnik_skali + przesuniecie  // 65.0

// Średnia z nawiasami
srednia_temp = (temp_1 + temp_2 + temp_3) / 3

// Modulo dla zdarzeń cyklicznych
reszta = licznik_petli % 10

# Binarne operatory logiczne

OperatorOpis
andLogiczne I - Zwraca true tylko jeśli oba operandy są true
orLogiczne LUB - Zwraca true jeśli przynajmniej jeden operand jest true. Oba operandy są zawsze wyliczane (brak skróconej ewaluacji).

Przykłady:

// Warunkowe oświetlenie (AND)
if (ruch_aktywny and poziom_jasnosci < prog) {
    ustawSwiatlo(true)
}

// Redundantne wyzwalanie (OR)
if (drzwi_otwarte or wibracja_okna) {
    wyzwolAlarm()
}

// Złożona logika (Grupowanie)
ogrzewanie_wl = reczne_nadpisanie or (jest_weekend and uzytkownik_w_domu)

# Binarne operacje bitowe

Operacje bitowe umożliwiają bezpośrednią manipulację pojedynczymi bitami w wartościach całkowitych.

OperatorOpis
&Bitowe AND
|Bitowe OR
xorBitowe XOR
shlPrzesunięcie w lewo
shrPrzesunięcie w prawo

Przykład - Bitowe AND do maskowania:

wartosc_czujnika = 0xA7    // Binarnie: 1010 0111
maska = 0x0F               // Binarnie: 0000 1111

// Wyodrębnij tylko dolne 4 bity
dolny_nibble = wartosc_czujnika & maska
// Wynik: 0x07 (Binarnie: 0000 0111)
Kompletna dokumentacja języka Volang - autorskiego języka programowania Voldeno do automatyki inteligentnego domu.