A Fortress programozási nyelv
Utasítások, vezérlési szerkezetek
Programstruktúra
A Fortress-programok komponensekre vannak osztva. Minden forrásfájl egyetlen egy komponenst tartalmazhat.
Az "API" mint fogalom, beépített nyelvi elemnek minősűl. Vannak beépített APIk, és mi is irhatunk sajátokat.
Minden komponens deklarálhatja az általa megvalósított APIkat, illetve APIfüggőségeit.
api Executable
run(args:String...):()
end
Ez az API egyetlen egy függvényt, a run -t deklarálja, aminek a típusa (String...)->().
Ez egy nyíl-típus (lásd késöbb). A () az üres típus ("void" -nak ejtjük).
A Hello World így néz ki Fortressben:
component HelloWorld
export Executable
run(args) = print "Hello, world!"
end
Értékadás, üres utasítás
Az értékadás bal oldalán egy vagy több változó vagy mezőelérés található, amit egy ":=" jel követ,
majd ezt követi egy tetszőleges kifejezés.
Amennyiben több változónak szeretnénk értéket adni, úgy a felsorolást N-esbe kell szervezni (azaz vesszővel
elválasztani az értékeket, és bezárójelezni).
A ":=" operátor az egyszerű értékadás, melynel elösszor a jobb oldali kifejezés(ek) kiértékelése
történik meg (több kifejezés esetén párhuzamosan) a bal oldali kifejezés-csoporttal egyidőben,
majd maga az értékadás, páronként.
Az üres utasításra nincs kimondott nyelvi elem, esetleg üres blokkokat lehet definiálni.
Szekvencia
Kifejezések sorozatát egy do blokkba foglalhatjuk:
printThreeWords() = do
print "print"
print " three"
print " words"
end
Lehetőségünk van parallel kiértékelni kifejezéseket:
do
factorial(10)
also do
factorial(5)
also do
factorial(2)
end
Egyszerűbb formában is leírhatjuk ezt, egy N-es típusú kifejezés használatával:
(factorial(10), factorial(5), factorial(2))
A párhuzamos részek megfelelő interakcióinak tervezéséhez nyelvi szintű támogatás
van elemi blokkok készítésére; az ilyen blokkok hatása kétféleképp érvényesül:
a többi szál vagy úgy látja, hogy a blokk még nem futott le, vagy úgy látja, hogy
a blokk lefutott, azaz egyetlen egy lépésben érvényesült a blokkban végrehajtott utasítássorozat.
atomic do
x += 1
y += 1
end
Nézzünk meg egy komplexebb példát:
do
x:ZZ32 := 0
y:ZZ32 := 0
z:ZZ32 := 0
atomic do
x += 1
y += 1
also atomic do
z := x + y
end
z
end
A ZZ32 a 32 biten árbázolható, előjeles egész számok halmazát reprezentáló típus.
A kifejezés típusa z típusa lesz, értéke pedig z értéke, ami vagy 0, vagy 2 lehet,
ugyanis a sorrendiség nincs előírva a parallel futó részek számára, csak a tranzakcionáltság!
Elágazás
A nyelvben az if utasítást egy Boolean típusú kifejezés követi, majd egy "then" kulcsszó, majd
egy kifejezés(blokk).
Amennyiben más feltételeket is ki szeretnénk értékelni, úgy használhatunk "elif" blokkokat (az
"else if" helyett), melynek mindnek ugyanaz a szerkezete, mint a normál fornak.
Ha feltétel nélküli ágat szeretnénk megadni, az "else" kulcsszó használható.
Az if kifejezés típusa annak a kifejezésblokknak a típusa lesz, amelyet végül kiértékel. Ha ilyen
nem történik meg (pl nincs else ág), akkor a típusa () lesz.
Lezárható egy "end" kulcsszóval, akkor ezonban az else ág kötelező.
factorial(n) =
if n = 0 then 1
else n factorial(n-1) end
A nyelv ismeri a case utasítást is, amelyet egy feltételes utasítás, egy opcionális operátor, és
egy "of" követ, majd az esetek felsorolása, melyek mindegyike egy őrkifejezéssel kezdődik, amit
egy "=>" követ, majd a kifejezés(blokk).
Tartalmazhat egy opcionális else ágat (ahol az őrkifejezés helyére kerül az else kulcsszó.)
A végét end jelzi.
A case kifejezés kiértékeli a feltételes utasítását, majd sorban kiértékeli az őrkifejezéseket, majd
a megadott operátorral osszehasonlítja őket. Amennyiben nincs megadva operátor, úgy az egyenlő,
vagy a tartalmazás operátorok kerülnek használatra.
Ha ez kiértékelve igaz, akkor a kifejezés(blokk) kiértékelésre kerül.
Az opcionális else ág összehasonlítás nélkül kerül lefutásra, ha a többi ág nem elégítette ki a feltételt.
Speciális esete a casenek a typecase kifejezés, ahol egy kifejezés értékét lehet vizsgálni, és az alapján
elágaztatni (az x lokális változó itt deklarálódik, típusa a jobb oldali kifejezés típusa lesz).
Amennyiben immutable az, amit vizsgálni szeretnénk, úgy a lokális változó bevezetése elhagyható.
typecase x = myLoser.myField of
String => x "foo"
Number => x + 3
Object => yogiBerraAutograph
end
Ciklus
A nyelvben megtalálható a for és a while ciklus.
A while kulcsszó után egy feltételes kifejezés található, majd egy do blokk:
while x < 10 do
println x
x += 1
end
A for ciklusban a ciklusváltozót nem kell külön deklarálnunk, a típusa is kikövetkeztetésre kerül fordításkor.
A ciklusváltozó lokális konstans.
for i <- 1:10 do
print(i "")
end
Egy nagyon fontos különbség a Fortress és más nyelvek között, hogy a for ciklus
kiértékelése párhuzamosan történik alapesetben, azaz a fenti példakód tetszőleges
sorrendben (és akár futásonként eltérően!) írhatja ki a számokat.
Egyéb vezérlő utasítások
A try-catch-finally blokkal, illetve az exit utasítással van lehetőségünk még
megváltoztatni a vezérlési folyamot.