Razlogov za ustvarjanje jezika je več, nekateri pa niso takoj očitni. Rad bi jih predstavil skupaj s pristopom k oblikovanju jezika za Navidezni stroj Java (JVM), kolikor je mogoče ponovno uporabiti obstoječa orodja. Na ta način bomo zmanjšali razvojni napor in uporabniku zagotovili orodje, ki bo lažje pri sprejemanju našega novega programskega jezika.
V tem članku, prvem iz serije, bom predstavil pregled strategije in različnih orodij, ki sodelujejo pri ustvarjanju našega lastnega programskega jezika za JVM. v prihodnjih člankih se bomo poglobili v podrobnosti izvedbe.
Programskih jezikov je že neskončno veliko. Zakaj bi se torej trudili ustvarjati novega? Na to obstaja veliko možnih odgovorov.
Najprej obstaja veliko različnih vrst jezikov: ali želite ustvariti splošni programski jezik (GPL) ali domensko specifičen jezik? Prva vrsta vključuje jezike, kot so Java ali Scala: jeziki, namenjeni pisanju dovolj spodobnih rešitev za širok nabor problemov. Domain Specific Languages (DSL) se namesto tega osredotočajo na zelo dobro reševanje določenega sklopa težav. Pomislite na HTML ali lateks: lahko bi risali na zaslon ali ustvarjali dokumente v Javi, vendar bi bilo to okorno, s temi DSL-ji lahko dokumente ustvarite zelo enostavno, vendar so omejeni na določeno domeno.
Torej morda obstaja vrsta težav, pri katerih zelo pogosto delate in za katere bi bilo smiselno ustvariti DSL. Jezik, zaradi katerega bi bili zelo produktivni, ko bi vedno znova reševali enake probleme.
Morda namesto tega želite ustvariti GPL, ker ste imeli nekaj novih idej, na primer za zastopanje odnosi kot državljani prvega razreda ali predstavljajo kontekst .
Končno boste morda želeli ustvariti nov jezik, ker je zabaven, kul in ker se boste v tem procesu veliko naučili.
Dejstvo je, da če ciljate na JVM, lahko z manj truda pridobite uporaben jezik, in sicer zato, ker:
Torej se stroški razvoja jezika močno zmanjšajo na JVM in smiselno bi bilo ustvariti nove jezike v scenarijih, ki bi bili zunaj JVM neekonomični.
Obstaja nekaj orodij, ki jih morate nujno uporabljati v svojem jeziku - med njimi sta razčlenjevalnik in prevajalnik (ali tolmač). Vendar to ni dovolj. Če želite, da bo vaš jezik resnično uporaben v praksi, morate navesti številne druge sestavne dele verige orodij, ki se lahko integrirajo z obstoječimi orodji.
Idealno bi bilo, če bi bili sposobni:
Če boste to lahko storili, bo sprejetje vašega jezika veliko lažje.
Torej, kako lahko to dosežemo? V nadaljevanju prispevka preučujemo različne dele, ki jih potrebujemo, da to omogočimo.
Prva stvar, ki jo morate storiti za pretvorbo izvornih datotek v program, je razčlenitev, pri čemer dobite predstavitev informacij v kodi z abstraktno sintaksno drevo (AST). Takrat boste morali potrditi kodo: ali obstajajo sintaktične napake? Semantične napake? Vse jih morate najti in prijaviti uporabniku. Če gre vse gladko, morate še vedno razrešiti simbole. Ali se na primer nanaša »Seznam« java.util.List ali java.awt.List ? Ko prikličete preobremenjeno metodo, katero izberete? Na koncu morate za svoj program ustvariti bajtno kodo.
Torej, od izvorne kode do zbrane bytecode obstajajo tri glavne faze:
Poglejmo podrobno te faze.
Izdelava AST : razčlenjevanje je nekakšen rešen problem. Obstaja veliko okvirov, vendar predlagam, da uporabite ANTLR. Dobro je znan, dobro vzdrževan in ima nekaj funkcij, ki olajšajo določanje slovnic (obravnava manj rekurzivna pravila - tega vam ni treba razumeti, vendar bodite hvaležni!).
Analiza in preoblikovanje AST : pisanje sistema tipov, preverjanje veljavnosti in ločevanje simbolov bi lahko bilo zahtevno in bi zahtevalo precej dela. Samo za to temo bi bil potreben ločen prispevek. Za zdaj upoštevajte, da je to del vašega prevajalnika, za katerega boste namenili večino truda.
Izdelava bajtkode iz AST : ta zadnja faza pravzaprav ni tako težka. V prejšnji fazi bi morali razrešiti simbole in pripraviti teren, tako da lahko v bistvu prevedete posamezna vozlišča preoblikovanega AST v eno ali nekaj navodil bajtkode. Nadzorne strukture bi lahko zahtevale nekaj dodatnega dela, ker boste prevedli for-zanke, stikala, ifs in tako naprej v zaporedju pogojnih in brezpogojnih preskokov (da, pod vašim čudovitim jezikom bo še vedno kup gotojev). Naučiti se morate, kako JVM deluje interno, vendar dejanska izvedba ni tako težka.
Ko boste dosegli prevlado svojega jezika, bo vsa koda napisana izključno z njegovo uporabo. Vendar pa bo vaš jezik verjetno uporabljen skupaj z drugimi jeziki JVM kot vmesni korak. Morda bo nekdo začel v večjem projektu pisati nekaj razredov ali manjše module v vašem jeziku. Smiselno je pričakovati, da bi lahko mešali več jezikov JVM. Torej, kako to vpliva na vaša jezikovna orodja?
Upoštevati morate dva različna scenarija:
V prvem scenariju mora vaša koda uporabljati samo prevedeno kodo, napisano v drugih jezikih. Na primer, nekatere odvisnosti, kot je Guava ali moduli v istem projektu, je mogoče zbrati ločeno. Tovrstna integracija zahteva dve stvari: najprej bi morali biti sposobni interpretirati datoteke razredov, ki jih ustvarijo drugi jeziki, da bi jim razločili simbole in ustvarili bajtno kodo za klicanje teh razredov. Druga točka je odsevna za prvo: drugi moduli bodo morda želeli ponovno uporabiti kodo, napisano v vašem jeziku, potem ko bo prevedena. Zdaj to običajno ni problem, ker lahko Java komunicira z večino datotek razreda. Kljub temu vam je še vedno uspelo napisati datoteke razredov, ki so veljavne za JVM, vendar jih ni mogoče priklicati z Jave (na primer zato, ker uporabljate identifikatorje, ki v Javi niso veljavni).
Drugi scenarij je bolj zapleten: predpostavimo, da imate razred A definiran v kodi Java in razred B, napisan v vašem jeziku. Recimo, da se dva razreda nanašata drug na drugega (na primer A bi lahko razširil B in B lahko sprejel A kot parameter za isto metodo). Zdaj je bistvo v tem, da prevajalnik Java ne more obdelati kode v vašem jeziku, zato mu morate zagotoviti datoteko razreda za razred B. Za sestavljanje razreda B pa morate vstaviti sklice na razred A. Torej, kar morate storiti, je imeti nekakšen delni prevajalnik Java, ki lahko z izvorno datoteko Java tolmači in ustvari njen model, ki ga lahko uporabite za sestavljanje razreda B. Upoštevajte, da je za to treba razčleniti kodo Java (z uporabo nekaj podobnega JavaParser) in reševanje simbolov. Če nimate pojma, kje bi začeli, si oglejte java-simbol-reševalec .
Dobra novica je, da lahko dejstvo, da uporabljajo modul, napisan v vašem jeziku, uporabniku popolnoma pregleden, tako da razvijete vtičnik za gradle ali maven. Sistemu za gradnjo lahko naročite, da prevaja datoteke v vašem programskem jeziku. Uporabnik bo še naprej poganjal mvn compile ali gradle assemble in ne bo opazil nobene razlike.
Slaba novica je, da pisanje vtičnikov Maven ni enostavno: dokumentacija je zelo slaba, nerazumljiva in večinoma zastarela ali preprosto narobe . Da, ne sliši se tolažilno. Nisem še napisal gradle plugin, vendar se mi zdi veliko lažje.
Upoštevajte, da morate razmisliti tudi o tem, kako lahko izvajate teste s pomočjo sistema za gradnjo. Za podporne teste si omislite zelo osnovni okvir za enotno testiranje in bi ga morali integrirati s sistemom gradnje, tako da zagon testa maven išče teste v vašem jeziku, jih prevedite in zaženite, da uporabniku sporočite rezultate.
Moj nasvet je, da si ogledate primere, ki so na voljo: eden izmed njih je vtičnik Maven za Torinski programski jezik .
Ko ga implementirate, bi lahko vsi lahko zlahka sestavili izvorne datoteke, napisane v vašem jeziku, in jih uporabili v storitvah za neprekinjeno integracijo, kot je Travis.
Vtičnik za IDE bo najbolj vidno orodje za vaše uporabnike in nekaj, kar bo močno vplivalo na zaznavanje vašega jezika. Dober vtičnik lahko uporabniku pomaga pri učenju jezika s pametnim samodejnim dokončanjem, kontekstualnimi napakami in predlaganimi popravki.
Zdaj je najpogostejša strategija izbrati en IDE (običajno Eclipse ali IntelliJ IDEA) in zanj razviti poseben vtičnik. To je verjetno najbolj zapleten del vaše orodjarne. To je iz več razlogov: najprej ne morete smiselno ponovno uporabiti dela, ki ga boste porabili za razvoj vtičnika za en IDE za druge. Vaš Eclipse in vaš vtičnik IntelliJ bosta popolnoma ločena. Druga točka je, da je razvoj vtičnikov IDE nekaj zelo običajnega, zato ni veliko dokumentacije in skupnost je majhna. To pomeni, da boste morali porabiti veliko časa, da sami ugotovite, kaj. Osebno sem razvil vtičnike za Eclipse in za IntelliJ IDEA. Moja vprašanja na forumih Eclipse so ostala neodgovorjena mesece ali leta. Na forumih IntelliJ sem imel več sreče in včasih sem dobil odgovor od razvijalcev. Vendar je uporabniška baza razvijalcev vtičnikov manjša in API je zelo bizantinski. Pripravite se na trpljenje.
Vse to ima alternativo in jo je uporabiti Xtext . Xtext je okvir za razvoj vtičnikov za Eclipse, IntelliJ IDEA in splet. Rodil se je na Eclipse in je bil pred kratkim razširjen tako, da podpira druge platforme, zato na tem področju ni toliko izkušenj, vendar bi ga lahko razmislili o alternativi. Naj razjasnim: edini način za razvoj zelo dobrega vtičnika je, da ga razvijete z uporabo izvornega API-ja vsakega IDE-ja. Vendar pa lahko z Xtextom dobite nekaj primernega dostopa z delčkom truda - to preprosto dodelite sintaksi svojega jezika in sintaksne napake / dokončanje dobite brezplačno. Kljub temu morate uporabiti ločljivost simbolov in trde dele, vendar je to zelo zanimivo izhodišče; trdi deli pa so integracija s knjižnicami, specifičnimi za platformo, za reševanje simbolov Java, zato to v resnici ne bo rešilo vseh vaših težav.
Obstaja veliko načinov, kako lahko izgubite potencialne uporabnike, ki so se zanimali za vaš jezik. Sprejetje novega jezika je izziv, ker ga je treba naučiti in prilagoditi naše razvojne navade. Če čim bolj zmanjšate izčrpavanje in izkoristite ekosistem, ki je že znan vašim uporabnikom, lahko preprečite, da bi se uporabniki odrekli, preden se naučijo in se zaljubijo v vaš jezik.
V idealnem primeru bi lahko vaš uporabnik kloniral preprost projekt, napisan v vašem jeziku, in ga zgradil z uporabo standardna orodja (Maven ali Gradle), ne da bi opazili kakršno koli razliko. Če želi urediti projekt, ga lahko odpre v njegovem najljubšem urejevalniku, vtičnik pa mu bo pomagal opozoriti na napake in omogočil pametne zaključke. To je scenarij, ki se precej razlikuje od tega, da bi morali ugotoviti, kako sklicati prevajalnik in urejati datoteke s pomočjo beležnice. Ekosistem okoli vašega jezika lahko resnično spremeni in danes ga je mogoče zgraditi z razumnimi napori.
Moj nasvet je, da ste kreativni v svojem jeziku, ne pa tudi v svojih orodjih. Z znanimi standardi zmanjšajte začetne težave, s katerimi se ljudje soočajo, da bi sprejeli vaš jezik.
Veselo oblikovanje jezika!