lumen
Dynamicznie typowany język skryptowy w Kotlinie. Źródło jest skanowane, parsowane do AST, kompilowane do bytecode'u i wykonywane na stosowej maszynie wirtualnej.
Dynamicznie typowany język skryptowy w Kotlinie, który naprawdę wykonuje kod: skanowanie i parsowanie do AST, kompilacja do bytecode'u i uruchomienie na własnej stosowej maszynie wirtualnej.
Wprowadzenie
lumen to dynamicznie typowany język skryptowy napisany w Kotlinie, który naprawdę wykonuje kod. Źródło jest skanowane, parsowane do AST, kompilowane do bytecode'u, a na końcu uruchamiane na własnej stosowej maszynie wirtualnej. Wygląda jak zwykły język skryptowy, ale pod spodem każda linijka przechodzi pełną drogę od tekstu do instrukcji maszyny.
Różnica między lumen a typowym ćwiczeniem z pisania języka leży w tym jednym słowie: bytecode. Łatwo zbudować interpreter, który chodzi po drzewie i liczy je na bieżąco. lumen idzie o krok dalej i kompiluje, co jest zarazem trudniejsze i o wiele ciekawsze.
Interpreter chodzący po drzewie składniowym jest prosty do napisania, ale szybko trafia na sufit wydajności. Każde wykonanie tej samej pętli oznacza ponowne przechodzenie tych samych węzłów drzewa, z całym narzutem, jaki to niesie. Dla małego skryptu to niewidoczne, dla czegokolwiek większego - odczuwalne.
lumen wybiera trudniejszą, ale lepszą drogę: zamiast wykonywać drzewo, kompiluje je do bytecode'u, czyli płaskiej listy prostych instrukcji. Te instrukcje chodzą potem na maszynie wirtualnej, która nie musi już nic rozumieć ze składni - dostaje gotowe rozkazy i po prostu je wykonuje.
Od tekstu do bytecode'u
Cała droga rozkłada się na cztery etapy. Skaner tnie tekst na tokeny, parser układa je w drzewo, kompilator zamienia drzewo w bytecode, a maszyna wirtualna wykonuje ten bytecode instrukcja po instrukcji. Wygląda to jak zwykły kod, ale każda linijka przechodzi tę samą pełną ścieżkę.
tekst źródłowy staje się tokenami.
tokeny układają się w drzewo składniowe (AST).
drzewo zamienia się w bytecode.
bytecode wykonuje się na stosie, instrukcja po instrukcji.
Maszyna stosowa od środka
Maszyna stosowa nie ma rejestrów jak prawdziwy procesor - operandy odkłada i zdejmuje ze stosu. Dodawanie sprowadza się do trzech ruchów: odłóż dwie liczby, zdejmij je i dodaj, odłóż wynik. Ten sam model napędza pod spodem między innymi Pythona i Javę, więc pisanie go samemu to zajrzenie w to, jak działają języki, których używa się na co dzień.
Dodawanie na maszynie stosowej
| Krok | Instrukcja | Stos po operacji |
|---|---|---|
| 1 | odłóż 2 | 2 |
| 2 | odłóż 3 | 2, 3 |
| 3 | dodaj | 5 |
Maszyna stosowa działa bez rejestrów, a mimo to potrafi wykonać dowolny program. Cała arytmetyka i przekazywanie wartości odbywają się przez jeden stos - to zaskakująco proste, a zarazem dokładnie ten sam pomysł, który napędza duże języki produkcyjne.
Efekt: słowo "skompilowane" przestaje być abstrakcją
Na wyjściu jest język, który naprawdę wykonuje kod - nie interpretuje drzewa na bieżąco, tylko kompiluje je i uruchamia na własnej maszynie. To projekt, po którym słowo "skompilowane" przestaje być abstrakcją, bo samemu przeszło się całą drogę od znaku w pliku do instrukcji, która coś robi. Mały język, ale kompletny aż do samego wykonania.
Więcej projektów
Inne realizacje z tej samej kategorii - zobacz, jak podchodzimy do podobnych wyzwań.
Masz podobny projekt?
Napisz do nas - wycena jest bezpłatna i wraca w godzinę.



