Hermes programozási nyelv

Típusok, típuskonstrukciók

Elemi típusok

A típusokat megengedett műveleteik alapján a készítõk típuscsaládokba sorolták. A más nyelvekbõl már jól megszokott típusok itt, mint elõredefiniált típusok használhatók.( pl.: predefined!integer)

Skalár típus(ok)

A Skalárt a nominális, felsorolási, logikai, egész és valós típuscsaládok alkotják.

A nominális tartomány értékeknek olyan halmaza amelyek között az egyetlen alkalmazható művelet az egyenlőség vizsgálata. Egyedi nevek előállítására használatos, generálásuk a unique operátorral lehetséges. Másolhatjuk őket illetve tesztelhetjük az egyenlőségüket, azonban integer konverzióra nincs lehetőség. Két érték akkor és csak akkor egyenlő, ha ugyanazon generált értékek másolatai.

A felsorolási típuscsalád kulcsszava az enumeration, amelyben véges sok nevezett típusú karaktersorozatot adhatunk meg, amelyek a felsorolásban elfoglalt helyük szerint bírnak számértékkel; az ordered kulcsszó megadásával már nem csupán az egyenlőség vizsgáltra korlátozódnak az alkalmazható műveleteink, hanem rendezettségi összehasonlítás is végezhető.

például:

jegyek : ordered enumeration (' elégtelen','elégséges', 'közepes', 'jó','jeles')

A logikai tartomány két különböző értékkel rendelkezik, a true és a false értékek reprezentánsaival. Alkalmazható műveletei ugyanazok mint a rendezetlen felsorolási típuséi, illetve a logikai and or és not műveletek.

például:

bit : boolean (true:'0', false: '1');

Az integer tartomány a matematikai egészek tartománya. Minden integer definíció egy új integer tartományt definiál.

például:

 alma: integer;  narancs: integer;

Az 5 az alma integer tartományból nem hasonlítható össze a narancs tartománybeli 5-tel, de konverziós operátor segítségével a két tartomány már igény szerint kezelhető.

Néhány nyelvben az integer definíciója a következő: a számítógép memóriájabeli szóban elhelyezhető legnagyobb értékű számmal vett modulo. Ezzel szemben a Hermesben az integer matematikai definíciója van érvényben. Egy integer művelet eredménye vagy a matematikailag helyes eredmény vagy pedig értéket nem kapunk és egy Depletion kivétel váltódik ki.

A valós tartomány biztonságos számok halmazából áll. A biztonságos számok olyan diszkrét részhalmazát képezik a valós számoknak amelyek elegendően közel vannak ahhoz, hogy kielégítsék a felhasználó által definiált pontosság mértékét. Minden valós számhoz létezik egy olyan biztonságos szám amelynek a relatív hibája (a valós és a biztonságos szám közötti távolság és a valós szám hányadosa) kisebb vagy egyenlő a pontossági feltétellel.

A pontosság tört formában fejezendő ki., pl.: 1/10000000.

például:

  sebesség: real of accuracy 1/100000;

A biztonságos számokkal kapcsolatos implicit feltételezés:
A 0 biztonságos szám; továbbá ajánlatos a biztonságos számok szerepére az integer értékeket használni..

Az integer és a real típusok műveletei az összeadás, kivonás, szorzás, osztás és a negálás (unáris minusz).
Egész szám egésszel való osztása esetén csonkítás lép fel.

Egyéb műveletek a rem és a mod. a rem b esetén a/b maradékát kapjuk, míg a mod b esetén az érték előjele megegyezik b előjelével, abszolút értéke kisebb mint b abszolút értéke és kielégíti az a=bn+(a mod b) egyenlőséget valamilyen n értékre. Nullával való osztás, illetve a rem és mod műveletek használata 0 értékű második operandussal a DivideByZero kivétel kiváltását eredményezik.

A <,>,<=,>= relációk megengedettek. értékük boolean típusú, ami nem feltétlenül predefined!boolean.

Az and, or, not műveletek minden boolean típusra megengedettek. Különböző boolean típusú operandusok vegyes használata tisztán nem lehetséges, konverzió szükséges.

Nominális típusú egyedi érték generálására a unique művelet használatos.

például:

  Z <- unique;.

Felsorolási típus esetén a:

for felsorolási-változó : felsorolási-típus repeat [ utasítások;] ... end for

művelettel egy rendezetlen felsorolási típus elemeit járhatjuk be. Minden tartománybeli értéket felvesz a változó, de a kiválasztás nemdeterminisztikusan történik.

Rendezett típus konverziójára a convert of operátor alkalmazható.

példa:

 x <- convert of y;

A három rendezett tartomány közötti összefüggés a következő:
 rendezett felsorolási része az integernek, az része a realnek

Összetett típusok

A rekord típus család:

A rekord értékek sora, úgynevezett komponenseké. Inicializálás után a komponens változók már léteznek. A komponens változók ezen felül inicializált vagy nem inicializáltak lehetnek. Nem inicializált rekordban a komponens változók nem léteznek. Ezeket inicializálatlanoknak tekintjük és ezek nem is tehetők inicializáltakká.

Két rekord összehasonlításkor megegyezik ha ugyanazon komponensei inicializáltak és minden ilyen komponens egyenlő.

A rekord típus definíciója nevet és típus rendel minden komponenshez.

például:

 kloz: record ( id: klozid,  állapot: állapot  );

A new operátorral lehetséges olyan inicializált rekord készítése melynek komponensei inicializálatlanok. Abban az esetben, ha a rekord korábban értékkel rendelkezett, ez az érték eldobásra kerül.

Olyan rekordok inicializálására melyek komponensei inicializálatlanok, két mód van. Az egyik a new operátor használata, a másik pedig egy korábban létező rekord érték hozzárendelése vagy belemozgatása.

A tábla típus család:

konstrukciója:

  ::= [ordered] table of elem-típus elem-típusállapot        [key [key] ....]

key ::= ( [ formális-változó [, formális-változó] ... ] )

A tábla azonos típusú és típusállapotú értékek kollekciója. Az értékeket a tábla elemeinek nevezzük, típusa az elem típus és típusállapota az elem típusállapot. Táblák használatával zsákok, halmazok, sztringek, tömbök, listák és relációk valósíthatók meg.

A tábla típus definíciója tartalmaz egy elem típust és elem típusállapotot reprezentáló formális típusállapotot. Továbbá az ordered kulcsszó is használható. A tábla típus definíciója kulcsok halmazát is tartalmazhatja. Mindegyik kulcs formális változók listájaként irandó fel.

Megszorítások: A kulcsváltozóknak inicializáltaknak kell lenniük.. Az elem típusállapotnak nem kell teljesen inicializáltnak lennie. Ezen megszorítások garantálják a tábla elemeinek és kulcsainak összehasonlíthatóságát.

Ha a táblának több kulcsa van bármely két táblabeli elem különböző értékekkel fog rendelkezni minden kulcsra vonatkozóan. Akkor mondjuk, hogy két elem egy kulcsban eltér, ha azon kulcs bármely változójában eltérnek.

Rendezett tábla értéke rendezett, esetlegesen üres elemhalmaz. A tábla első eleme a 0-ás pozíción helyezkedik el, a következő az 1.-en, stb.

Két rendezett tábla egyenlő, amennyiben egyenlő elemeket tartalmaznak ugyanabban a sorrendben.

Két rendezetlen tábla egyenlő, ha elemei egyértelműen megfeleltethetők egymásnak és a megfeleltetett párok egyenlőek.

példák:

 intbag:           table of integer { init };  string:            ordered table of char { init };  string set:       table of string {init} keys (*);

 szemelyek:    table of person { full } keys ( name, adress) (id);

A new művelet itt is használható, eredményeképpen egy inicializált, de üres tábla jön létre. Amennyiben a tábla rendelkezett korábbi értékekkel, az értékek eldobásra kerülnek.

Két rendezett tábla összefűzésére a concat művelet szolgál. Az elemeknek másolhatónak kell lenniük.

Szelektor használatára három különböző szintaxisú formula létezik. Az első az úgy nevezett long selector, a másik kettő pedig mapping selector. A mapping selectorok a long selector egyszerű rövidítései.

alap-változó in tábla-változó where (szelekciós-kifejezés) alap-változó in tábla-változó [[ kifejezés [, kifejezés] ...] ] tábla-változó [[ kifejezés [, kifejezés ] ...] ]

A tábla-változó a tábla neve. Az alap változó egy szelektorban elem deklaráció, melynek típusa a tábla elem típusa. Ez a változó név a where kifejezésén belül látható. A kifejezés kiértékelése után olyan értéket eredményez amely predefined!boolean típusú.

Végrehajtási időben a szelektor kiérétkelése egyszer történik meg minden táblabeli elemre. Az elem változó értéke egy konstas másolata az elemnek. Azon elemeket kiválasztottnak tekintjük amelyekre a szelekciós kifejezés igaz.

A mapping selector-ok a szelektorok gyakori használatából eredő rövidítések. Ha a listájuk üres, a tábla összes eleme kiválasztásra kerül (megfelel a where('true')-nak).Abban az esetben, ha a lista egyetlen kifejezésből áll, akkor feltételezzük , hogy a kifejezés egy pozíció és a kiválasztott elem a meghatározott pozíción lévő elem. A t[n] rövidített írása az e in t where(position of e=n).

Ha a fenti állítás nem igaz, azaz a lista k kifejezést tartalmaz illetve egy kulcs k változót, a k kifejezésről feltételezzük, hogy öszzehasonlítás azon kulcsok között. így például t[x,y] rövidített írása az e in t where (e.name=x and e.adress=y) kifejezésnek. Amennyiben ezek egyike sem igaz, úgy mapping selector -ok használata illegális.

Egyetlen elem kiválasztása esetén akkor, ha az elem nem létezik a NotFound kivétel váltódik ki.

Több elem kiválasztása esetén, rendezett tábálban a legkorábbi lesz a kijelölt kiválasztott. Rendezetlen esetben tetszőlegesen választ a nyelv.

Az every of szelektor egy olyan táblával tér vissza amely a kiválasztott elemek mindegyikének másolatát tartalmazza.A másolatok sorrendje megfelel az eredeti sorrendnek.

Az exist of operátor igaz értékkel tér vissza amennyiben a kiválasztandó elem létezik, egyébként hamissal.

A forall of szelektor eredménye igaz, ha minden elem kiválasztásra került, egyébként hamis.

Beszúrásra az insert, insert-at műveletek használatosak.
 

::= insert elem-kifejezés into tábla-változó [ at pozíció-kifejezés]

A művelet a forrásváltozó értékét a táblába mozgatja, ha annak típusa megfelelő. Ha a típusállapota alacsonyabb, akkor a művelet illegális. Ellenkező esetben a típusállapot lentebb kerül.

Rendezett tábla esetén az elem a tábla végére kerül.
Kulccsal ellátott tábla esetén, ha az elem az egyedi kulcsok feltételét megszegi DuplicateKey kivétel kerül kiváltásra.

Insert-at csak rendezett táblák esetén használható. Amennyiben a kívánt pozíció értéke negatív vagy nagyobb az elemszámnál akkor RangeError váltódik ki. Egyéb esetekben az elem a kért helyre kerül. Az előtte lévő elemek pozíció számai nem változnak, az utána levőké automatikusan növelődik eggyel.

Insert, insert-at műveletek után az elem változó inicializálatlan lesz, mivel az érték mozgatva lett nem pedig másolva.

A remove művelet két operandusú művelet: a cél elem az első a szelektor a második. A kiválsztott elem a cél elembe töltődik és a táblából eltávolításra kerül. Nem létezése esetén NotFound kivétel váltódik ki. A cél változó esetleges korábbi értéke eldobásra kerül.

alakja:
 

remove
elem-változó from szelektor

Az extract
alakja
:
  extract tábla-változó from szelektor

melynek segítségével minden kiválasztott elem a táblából eltávolításra kerül és a kívánt táblába mozog.

A Merge, merge-at alakja:
  merge tábla-kifejezés into tábla-változó [at pozíció-kifejezés]

A merge utasítás a forrás tábla tartalmát a cél táblába mozgatja. A két tábla típusazonossága azt jelenti, hogy az elemek ugyanazon típusú és típusállapotúak lesznek. Normális befejezés esetén a forrás tábla inicializálatlan lesz. A művelet rendezett táblák esetén sorrendtartó. Az összeolvasztás a tábla végénél történik. Duplikált kulcsok veszélye fennállhat.

A merge-at csak rendezett táblákkal lehetséges. Működése a merge-vel azonos, eltérés az olvasztási kezdőpont. Negatív szám illetve a létező elemszám túllépése esetén RangeError kivétel váltódik ki. Egyébként pedig az összeolvasztás a kívánt pozíciótól történik. Az előtte elhelyezkedő elemek pozíció száma nem változik, míg a többié a beolvasztott elemszámmal megnő.

Az inspect alakja:   ::inspect szelektor begin      [utasítások;]...     end inspect

Ez az utasítás a kiválasztott elemek konstans másolatát készíti el. Ez a másolat egy új változóban kerül eltárolásra. Az inspect-változó neve megegyezik a szelektor elem-változójának nevével, melynek deklarációja automatikusan történik a tábla elemtípusára és láthatósági köre az inspect utasítás törzsére is kiterjed.

Konstans másolat készítése mindig legális. Az általános másolatoké viszont bizonyos értékek esetén nem lehetésges, például ( callmessage-ek, input portok, vagy őket tartalmazó változók). Ezekre vonatkozó veszélyes műveletek a konstans másolatokon nem engedélyezettek.

A for-inspect alakja:  

:: for szelektor inspect      [utasítások;] ...    end for

Amely egy tábla/résztábla elemeinek bejárására szolgál. A tábla szükségszerűen inicializált. Egy változó ugyanazon névvel mint a szelektor elem változója a kiválasztott elem konstans másolatát tartalmazza. A tábla iterátoron belüli bárminemű megváltoztatása nem lesz kihatással a választott értékekre, mivel a for-inspect-be lépéskor meglévő táblabeli elemek képezik a további lépések munkatábláját.

Rendezett esetben a kiválasztás sorrendtartó.

A size of művelet inicializált tábla elemszámát adja meg.

A position of művelet kizárólag csak rendezett táblából kiválasztott elemek konstans másolataira alkalmazható. Ezek a konstans másolatok pedig csak szelektor kifejezések, inspect, for-inspect eredményéből születhetnek.

A művelet eredménye olyan egész amely azon kiválasztott elem pozíciója melynek konstans másolatát tartalmazza az elem változó. A pozíciók 0-tól kezdődnek.

példa:

 string <- "abcabd";
 inspect c in string where (c='b')  begin
     p<- position of c; end inspect;

A p változó értékül 1-et kap, azaz az első 'b' pozícióját a stringben.

A position of szelektor megkeresi a rendezett táblában ez első kiválasztott elemet majd meghatározza a pozícióját.

A variáns típus család

konstrukciója:
 

::= variant of felsorolási-típus (        [ eset-deklaráció [, eset-deklaráció] ... ]
  )

eset-deklaráció
  ::= nevezett-literál -> komponens-deklaráció komponens-típusállapot

A variáns értéke azon rögzített értékek egyike amelyek az előre kikötött típushalmazból valók. Mivel Hermesben minden változónak pontosan egy típusa van ezért különböző komponens nevekkel jelöljük az értékek különböző típusait. Egy V variáns lehet :

Két variáns egyenlő ha ugyanabban az esetben vannak és az így létező komponenseik egyenlőek.

A variáns típus komponensei egyértelműen megfeleltethetők egy felsorolási típus nevezett literáljainak. A nevezett literálokat hívjuk a variáns eseteinek és a felsorolási típus az eset típus.

példa:

id: charstring; lisptip: enumeration('nil','atom','pair'); s_kif: variant of lisptip ( 'nil' -> null: empty {}, 'atom' -> atom: id {init}, 'pair' -> pair: ccell {full} );

 ccell: record ( car: s_kif, cdr: s_kif );

Ebben a példában ha V egy s_kif típusú variáns és 'pair' előfordulásaú akkor a típusállapotok a következőek lesznek: init(V) case(V,V.pair) init(V.pair) init(V.pair.car) init(V.pair.cdr)

Unite segítségével egy variánst inicializálhatunk valamelyik esetére.
 alakja:
 
::= unite variáns-komponens from kezdeti-kifejezés

Az első operandus a komponens kijelölésére szolgál, míg a második egy kifejezés ami kiértékelése után a variáns-komponens típusával megegyező kell legyen. A kifejezés típusállapota legalább olyan magas kell, hogy legyen mint a komponens esetének típusállapota.

Végrehajtása után a kifejezés értéke a variáns komponensébe átmozog, majd a komponens felfedésre kerül és elérhetővé válik

Ennek ellentettje a dissolve művelet,
  ::= dissolve variáns-komponens into eredmény-változó

amelyben a kívánt komponens kijelölése után a komponens értékét a vele azonos típusú eredmény-változóba átmozgatjuk. A művelet után a variáns inicializálatlan állapotba kerül és a cél változó típusállapot attribútumai a variáns komponenstől szintén átkerülnek.

A már korábban említett állapotok elérésére szolgáló műveletek a reveal és a hide
 :: reveal variáns-komponens
 :: hide variáns-komponens

melyek a kijelölt komponens felfedését illetve elrejtését végzik.

Az esetek lekérdezésére szolgáló művelet a case of művelet amely az operandusként kapott variánsból az adott eset típusának értékét tartalmazó változót eredményez.