Wrzucam kod zrealizowanego w jakoś 20% projektu języka programowania oraz implementacji kompilatora w C# - ok. 100 commitów + CI bot.
Jako compilation target wybrane jest WebAssembly, a jako język pośredni użyty jest LLVM IR.
LLVM IR jest emitowane z ręki, a WebAssembly już przy pomocy LLVMa
Parser jest handwritten
Przykładowo dla takiego kodu
namespace Test
public int Test(int a, int b)
{
if (a > b)
{
return a + b;
}
else
{
return a - Qwert();
}
}
public int Qwert()
{
return 10 * 10;
}
Generowane jest takie IR:
Które następnie LLVM Optimizer optymalizuje do
; ModuleID = 'main.ll'
source_filename = "main.ll"
; Function Attrs: nofree norecurse nosync nounwind readnone willreturn mustprogress
define dso_local i32 @Test(i32 %0, i32 %1) local_unnamed_addr #0 {
%3 = icmp sgt i32 %0, %1
%4 = select i1 %3, i32 %1, i32 -100
%5 = add i32 %4, %0
ret i32 %5
}
; Function Attrs: nofree norecurse nosync nounwind readnone willreturn mustprogress
define dso_local i32 @Qwert() local_unnamed_addr #0 {
ret i32 100
}
attributes #0 = { nofree norecurse nosync nounwind readnone willreturn mustprogress }
I użycie na stronie (fetch("main.wasm")
):
Wrzucam to głównie po to, aby ktoś ciekawy mógł zobaczyć jak podejść do tego typu problemu, ale też aby mieć większą motywację do pisania tego.
Jako że nie oczekuje że ktoś będzie się tym chciał pobawić, co najwyżej przeglądnąć kod, to nie tracę czasu na pisanie jak to odpalić (chociaż do samego wyemitowania IR powinno działać out of the box bez żadnych konfiguracji / zabaw z LLVMem). Jeżeli będzie potrzeba, to dajcie znać .
Generalnie jest tutaj bardzo dużo czasochłonnych rzeczy do zrobienia, typu:
- CLI
- Language Server Protocol Support (VS Code)
- Zaprojektować język (OOP? FP? Other?)
- Dokumentacja Języka
- Podpięcie do repo binarek LLVMa, aby nie trzeba było samemu go kompilować
- Przepisanie niektórych rzeczy (Type Checker Pass, Expression Builder)
- Usprawnienie CI bota który po każdym commicie podnosi wersję projektu oraz wpushowuje dane z benchmarków
- Ogarnięcie Repo
- Rozważenie czy nie dodać też wsparcia dla czego innego niż WASM, aby to np. można było bezpośrednio z CLI używać jak normalne programy. Wymagałoby to dodania wsparcia dla jakichś printfów itd.
- Multi File Support (not tested yet)
- Parallel Lexer
- wiele więcej
Z rzeczy które są już w jakimś stopniu zrobione:
- Głównie fundamenty
- Jakaś infrastruktura
- Expression Builder,
- Otypowywanie drzewka,
- Passes,
- Graphviz code gen,
- LLVM IR code gen,
- Jakaś obsługa błędów,
- bieda CI do benchmarków
Wygenerowany Graphviz dla pierwszego kodu:
Czy warto w takie coś się pobawić?
Uważam że tak, pomimo tego że jest to czasochłonne gdy chcemy się na ile się da zbliżyć do prawdziwych projektów, oraz że wymaga trochę wstępu teoretycznego, to żaden inny projekt nie dał mi tyle, polecam :P
Przy okazji podczas developmentu tego projektu znalazłem różne bugi / dziwne zachowania w np. .NET CLI czy bibliotekach typu BenchmarkDotNet :D
- screenshot-20220730164811.png (32 KB) - ściągnięć: 9
- screenshot-20220730165400.png (21 KB) - ściągnięć: 9
- screenshot-20220730170417.png (19 KB) - ściągnięć: 6
- screenshot-20220730170552.png (133 KB) - ściągnięć: 9
- screenshot-20220730170628.png (24 KB) - ściągnięć: 6