Dostępność

Garść ogłoszeń pod choinkę

Krzysztof Wodnicki, 23 grudnia 2024

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?

Architektura kompilatora

Uproszczony schemat architektury kompilatora

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!