Wesołych Świąt i szczęśliwego Nowego Roku!
W związku ze zbliżającym się okresem świąteczno-sylwestrowym zespół DuckType przygotował dla was kilka prezentów.
Newsletter
Zacznijmy od newslettera, do którego już od jakiegoś czasu można się było zapisać na naszej stronie. Niestety z powodu drobnych problemów technicznych, ten kanał komunikacji pozostawał do tej pory nieużywany. Na szczęście już się uporaliśmy z tymi problemami i newsletter rusza wraz z wyjściem tego świątecznego posta.
Subreddit Ducklinga
Niedawno ogłaszaliśmy otwarcie bloga. Aby dodatkowo zwiększyć nasze możliwości budowania społeczności i kontaktu z wami, uruchamiamy też Ducklingowego subreddita. Oprócz dyskusji poświęconych językowi, kompilatorowi i maszynie wirtualnej, zachęcamy was do dzielenia się przemyśleniami na temat treści, które publikujemy na blogu. Planujemy, aby każdy artykuł miał swój wątek, w którym społeczność będzie mogła odpowiedzieć na udostępniane na blogu artykuły.
Serdecznie zachęcamy was do dołączenia i zaangażowania się w powstającą tam społeczność!
Pierwszy skompilowany program
Kolejny prezent którym chcemy się z wami podzielić to pierwszy w pełni skompilowany program napisany w Ducklingu!
fun main() = {
return;
}
Ci z was, którzy mają trochę doświadczenia z programowaniem pewnie zauważą, że... nie robi on nic? Dokładnie tak, program definiuje główną funkcję, która zwraca pustą wartość — to nie jest zbyt imponujące. Dlaczego więc jest to takie duże osiągnięcie? Mimo tego, że napisany kod niewiele robi to kompilator pod maską robi bardzo dużo. Nasz zespół kładzie nacisk na rozwój poszczególnych modułów kompilatora w taki sposób, aby dodawanie nowych elementów języka było jak najprostsze i nie wymagało podważania wcześniej podjętych decyzji. W związku z tym, ostatnim etapom kompilacji nie poświęcaliśmy na razie zbyt dużo uwagi, a sam kompilator rozwijał się raczej "wszerz" niż "wzwyż".
Co w takim razie robi kompilator?
Skoro wcześniejsze etapy kompilacji pochłonęły najwięcej naszej uwagi, warto zapytać, na ile są one dopracowane. Co dzieje się na wcześniejszych etapach kompilacji? Jak w ogóle przebiega kompilacja?
Parser
Kompilacja zaczyna się od skanowania folderu z modułem. Znajdowany jest główny plik modułu, który nastepnie jest parsowany do PST
(z ang: Parser Syntax Tree) — drzewiastej struktury, w której są już rozpoznane takie elementy kodu jak funkcje, wyrażenia, instrukcje czy deklaracje. Jest to odpowiednik struktury danych, która zazwyczaj w kompilatorach nazywana jest Abstract Syntax Tree.
HELIoS
Nastepnie drzewo parsowania trafia do modułu HELIoS
(z ang: Holistic Examination and Logical Inference of Semantics). Znajduje on główną funkcję main
i kompiluje ją do pośredniej reprezentacji HOUT
(HELIoS
-output).
HELIoS
wykonuje znaczną część analizy semantycznej, czyli analizuje faktyczne znaczenie programu, wykrywa wiele błędów oraz generuje prostsze reprezentacje kodu, bliższe językowi procesora. W trakcie swojej pracy, HELIoS
między innymi:
- znajduje deklaracje funkcji, zmiennych i innych elementów kodu,
- wiąże wszystkie nazwy w programie, czyli przypisuje identyfikatory do definicji,
- identyfikuje typy wszystkich symboli i sprawdza zgodność typów (z ang: type-check),
- rozwija makra i dokonuje ewaluacji czasu kompilacji,
- tworzy instancje typów i funkcji generycznych.
HELIoS
generuje reprezentację HOUT
(HELIoS
output), która jest podzielona na HU
(HOUT
unity). Pojedynczy HU
reprezentuje spójny fragment kodu, na przykład funkcję, klasę, przestrzeń nazw, a nawet cały moduł lub paczkę.
MIR i LIR
Następnie kompilator sprowadza każdy HU
do MIR
(z ang: Middle Intermediate Representation). Na tym etapie wstawia wywołania destruktorów i sprawdza poprawność tzw. semantyki przenoszenia. W przyszłości, MIR
zostanie wzbogacony o kilka innych weryfikacji. MIR
jest kompilowany do LIR
(z ang: Low Intermediate Representation), którego celem jest udogodnienie kompilacji do różnych backendów.
LLVM
Na ten moment głównym backendem jest LLVM, ale docelowo będziemy wspierać również drugi bardzo ważny backend, czyli naszą własną maszynę wirtualną (o której na pewno jeszcze dużo przeczytacie).
Dla każdego kompilowanego HU
kompilator emituje moduł LLVM. Następnie przy użyciu LLVM dokonywane są optymalizacje i produkowany jest gotowy plik wykonywalny.
To z pewnością brzmi dużo lepiej niż program, który nic nie robi!
Meet the compiler
Oczywiście taki telegraficzny skrót pracy kompilatora nadal pozostawia wiele pytań. Żeby zaspokoić waszą ciekawość przychodzimy z ostatnim na dziś prezentem - od początku przyszłego roku na naszym blogu regularnie będą pojawiać się wpisy z serii Meet the compiler
.
Jak nazwa wskazuje, seria będzie poświęcona technologii kompilatorów oraz działaniu tworzonego przez nas kompilatora Ducklinga. Możecie spodziewać się, że seria będzie prowadzona przede wszystkim w języku angielskim (nie wszystkie artykułu będą tłumaczone na język polski).
Serdeczne życzenia od zespołu DuckType
Mamy nadzieję, że dzisiejsze informacje były dla was ciekawe i zachęcą was do dalszego śledzenia postępów w projekcie. Jeszcze raz zapraszamy was do dołączenia do naszego subreddita i oczekiwania na nową serię Meet the compiler
.
Tymczasem cały zespół DuckType życzy wam wesołych Świąt i szczęśliwego Nowego Roku!