Amikor a Microsoft Managed Languages csapata 2013. decemberében bejelentette, hogy a korábbi C# és Visual Basic fordítót lecserélték, és már a Visual Studio következő verziójának napi buildjei is egy új fordítóval készülnek, hirtelen mindenki számára egyértelművé vált, hogy valami nagyon komoly dolog van készülőben. Az új, “Roslyn” kódnevű eszköz messze túlmutat a korábbi csc.exe és vbc.exe képességein és lehetőségein, nem véletlenül kapta végül a .NET Compiler Platform elnevezést.
Itt ugyanis nem egyszerűen arról van szó, hogy szeretnénk a forráskódunkat futtatható formára alakítani, hiszen arra már sok éve volt kiváló eszközünk. A Roslyn célja, hogy a fordító tudását API-kon keresztül megnyissa a fejlesztők és a fejlesztőkörnyezetek (például a Visual Studio) előtt, azaz egy fordító-mint-szolgáltatás (compiler-as-a-service) megoldásról beszélhetünk.
Miért van erre szükség? Leginkább azért, mert a fordítók nagyon összetett szerkezetek, és futásuk közben igen komoly mennyiségű információval rendelkeznek a forráskódunkról:
Ezt a tudást vétek bezárni egyetlen eszközbe, sokkal jobban járunk, ha a fordító által felhalmozott információkból más eszközök is mazsolázhatnak. A fordító az egyetlen eszközünk, amely valóban érti a forráskódunkat, hiszen a kód minden egyes betűjéről tudja, hogy az utasítás, adat, komment stb. Ezt felhasználva sokkal jobb fejlesztőeszközöket készíthetünk, például a Visual Studio 2015 kódszerkesztőjében számos funkció a Roslyn nélkül valószínűleg soha nem valósulhatott volna meg.
Az alábbi ábra a Roslyn platform felépítését mutatja (katt a teljes képért):
Aki szeretne minden egyes dobozt megérteni, bátran látogasson el a projekt honlapjára, én itt most csak annyit emelnék ki, hogy a forráskód olvasásától az értelmezésén keresztül egészen a futtatható kód generálásáig megtalálható itt minden, és mivel platformról van szó, természetesen mindenhez van API.
A kulcs elem a sárgával bekeretezett Syntax Tree, ami a Parser által létrehozott belső reprezentációja a teljes forráskódunknak. Az ehhez tartozó API-t hívják Roslyn Syntax API-nak, aminek segítségével nem csak forráskódból értelmezhetjük a forráskódunkat, hanem módosíthatjuk is azt. Példaként vegyük az alábbi utasítást:
Regex.Match("my text", @"\pXXX");
Ebből a Roslyn az alábbi szintakszisfát építi fel:
(A példát az MSDN Magazine Use Roslyn to Write a Live Code Analyzer for Your API című cikkéből kölcsönöztem, amiben egy Visual Studio bővítményt készítenek erre alapozva.)
Hogy mi ezt a fát pusztán csak nézegetjük, elemezzük, vagy módosítjuk is, az már kizárólag csak rajtunk múlik.
Felismerte ezt a TypeScript csapat is, és az 1.3 verziótól kezdve már a Roslyn motor szolgáltatja Visual Studioban a kódszerkesztő funkciókhoz a szükséges adatokat. Ennek köszönhetően a TypeScript fordító architektúrája nem csak hogy jelentősen letisztult, hanem egyúttal könnyebben érthetővé is vált:
Történetünk szempontjából az egyik fontos komponens az alsó dobozban szereplő Parser, a másik pedig az Emitter. A Parser feladata, hogy felépítse az absztrakt szintakszisfát – jelen esetben a TypeScript forráskódból –, az Emitter feladata pedig, hogy a szintakszisfa alapján elkészítse a fordító kimenetét – jelen esetben JavaScript (.js), definíció (.d.ts) vagy source map (.js.map) formában.
Érdemes észrevenni, hogy a Roslyn és a TypeScript architektúrája teljesen hasonló: a forráskódból előbb fát építünk, majd a fából más nyelvű kódot generálunk. A Roslyn esetén ez C# –> fa –> IL, a TypeScript esetén egy TypeScript –> fa –> JavaScript.
Mivel a két fa azonos, összekapcsolhatjuk a kettőt és így máris eljutunk az alábbi megoldáshoz:
Azaz a Roslyn és a TypeScript felhasználásával képesek lehetünk C# forráskódot JavaScriptre fordítani!
A módszer előnye, hogy mivel közvetlenül a C# forráskódból indulunk ki (ellentétben például a JSIL projekttel, ahol Common Intermediate Language kódot fordítanak JavaScriptre), minden olyan információ rendelkezésünkre áll, ami a forráskódban még elérhető (például láthatóság, öröklés stb.), de egyébként a C# fordító kimenetén már nem jelenik meg. Mindez meglepően hatékony optimalizálási lehetőségeket nyújt!
Példaként vegyük a JSIL projekt oldalán elérhető Raytracer demót. A teljes C# forráskód 429 sor, a JSIL által készített JavaScript kód 793 sor. Mondhatnánk, hogy örülhetünk, hogy egyáltalán fut, csakhogy a memória kezelése korántsem optimális:
Ugyanezt a forráskódot a Roslyn Parser + TypeScript Emitter kombináción átfuttatva az alábbi eredményt kapjuk:
Az Internet Explorer Developer Toolsban (F12) lévő UI Responsiveness eszköz segítségével megmértük a CPU utilization és a Visual throughput (FPS) értékeket is, és mindkét mutató jelentősen jobb értékeket mutatott.
Persze a kedvezőbb memória gazdálkodás és a jobb teljesítmény nem jön ingyen, a generált kód nagyobb lett, összesen 1844 sor. A jelentős méretnövekedést az okozza, hogy az IL kóddal ellentétben a szintakszisfa tartalmaz információt az osztályokról és azokon belül a tagok láthatóságáról, amit JavaScriptben csak körülményesen lehet leképezni, de ha megtesszük (és a TypeScript Emitter meg tudja tenni), akkor több kód letöltése árán összességében jobb teljesítményt tudunk elérni. Más alkalmazások vizsgálata során is ugyanerre a megállapításra jutottunk.
A módszer természetesen nem csak böngésző alapú alkalmazásoknál, hanem natív JavaScript alkalmazásoknál, például Node.js környezetben is működik. A fejlesztés lépései a következők:
- Telepítsd a Node.js Tools for Visual Studio bővítményt, ami lehetővé teszi Node.js appok készítését Visual Studioval.
- Töltsd le a Node.js with C# bővítményt a Visual Studio Gallery oldaláról (hamarosan elérhetővé tesszük).
- Telepítés után meg fog jelenni Visual Studioban a C# projektek között egy “Node.js application” nevű projekt sablon, annak segítségével kell létrehozni a projektet.
- Írd meg az alkalmazásod forráskódját C#-ban, ehhez természetesen használhatod a Visual Studiot.
- A szokásos módon működik a debuggolás (F5) és a futtatás is. A projekt sablon tartalmazza a szükséges MSBuild targeteket, ami a Roslyn és a TypeScript segítségével előállítja a JavaScript kódot, amit azután a Node.js Tools for Visual Studio fog átadni a Node.js futtatókörnyezetnek.
Tesztelőket keresünk! A Visual Studio plugin publikálása előtt szeretnénk egy szélesebb körű tesztet végezni. Ha szívesen vállalkoznál erre, kérlek itt olvasd el az útmutatót, majd hagyj egy kommentet alább és felveszem veled a kapcsolatot!
Frissítés:
http://www.reddit.com/r/node/comments/31r872/write_your_nodejs_app_in_c_with_roslyn/