A Limbo programozási nyelv

Alprogramok, modulok

Szintaxis

A Limbo alprogramjai ugyanazon célt szolgálják, mint más strukturált, procedurális nyelvek alprogramjai: a program futása során végrehajtott utasításokat tartalmazzák.

A Limbo függvény általános alakja:

függvény_név(paraméterek): visszatérési_típus { utasítás }

Az paraméterek változó nevek és hozzájuk társított típusok vesszővel elválasztott listája. A függvény meghívásakor behelyettesítődnek a függvénybe. A függvénynek nem kötelező, hogy legyen paramétere, de üres zárójelpárt ekkor is írni kell a függvény_név mögé.

A vissztérési_típus határozza meg a visszatérési érték típusát, ami tetszőleges lehet. A függvénynek nem kötelező értékkel visszatérnie.

Az init függvény

Ha a programot Inferno shellből hajtjuk végre, a shell egy speciális, init-nek nevezett függvényt keres. Ez a függvény mondja meg a rendszernek, hol kezdődik a program végrehajtása. Bizonyos szemszögből a C main függvényének felel meg.
Az init függvénynek két paramétere van: ref Draw->Context és list of string.

ref Draw->Context

ref Draw->Context a képernyő adatainak kinyerésére szolgál, és a draw.m-ben definiálták. Ez az paraméter megadása akkor is kötelező, ha a program nem használ semmilyen grafikát. Ha nem használjuk, nil-re állíthatjuk.

list of string

A list of string parancssorból a modulhoz adható paraméterek listája. Ha a program nem használ parancssorban megadott paramétereket, nil-re állítható.
E függvény működését tekintve ekvivalens a C argv változójával.

Függvények deklarálása

A modul minden publikus függvényét deklarálni kell. A deklaráció hasonló a C és C++-beli függvény prototípusok deklarációjához. Meg kell adni a paraméterekre és a visszatérési érték típusára vonatkozó információkat. Ez lehetővé teszi a fordító számára a típusellenőrzést, ami biztosítja futási időben a típusbiztonságot.
A deklaráció általános alakja a következő:

function_name: fn(arguments): return_type;

A függvénydeklaráció hasonló az adatdeklarációhoz. Az fn kulcsszó jelzi, hogy az objektum "függvény" típusú.

A modulban nem deklarált függvények privát tagok. Külső modulból nem érhetők el. A fordító elvégzi a típus ellenőrzést a függvényhívások és függvénydefiníció ellenére is.

A következő példa egy olyan modul, amely két függvényt tartalmaz: a publikus init és egy privát függvényt.

implement Command; include "sys.m"; sys: Sys; include "draw.m"; Command: module { init: fn(nil: ref Draw->Context, argv: list of string); }; init(nil: ref Draw->Context, argv: list of string) { sys = load Sys Sys->PATH; for(i := 1; i <= 10; i++) { sys->print(" %2d %4d\n", i, sqr(i)); } sqr(n: int): int { return n*n; }

Függvény paraméterek

Ha a függvény rendelkezik paraméterekkel, átmeneti változókat kell deklarálnia, melyek felveszik a paraméterek értékét. A paraméterek a függvény belsejében úgy viselkednek, mint más lokális változók. A függvénybe való belépéskor jönnek létre, és a függvényből való kilépéskor megsemmisülnek.
Mivel a Limbo erősen típusos nyelv, a fordító ellenőrzi az paraméterek típusát a függvény deklarációjában, a definíciójában, és a meghívásakor is.
Ha ezek közül valamelyik nem egyezik meg, a fordító hibát jelez.

Érték ill. referencia szerinti paraméterátadás

Mivel a Limbo nem engedélyezi a pointerek használatát, ezért nincs általános referencia szerinti hívás/átadás mechanizmus. A referencia típusú paraméterek referencia szerint, minden más típusú paraméter érték szerint adódik át.

Ha az adat érték szerint adódik át, a fogadó függvény egy teljesen új változót hoz létre, ami tartalmazni fogja az átadott értéket. Ezen változó módosítása nem hat ki a hívó függvénybeli értékre.

Ha az adat referencia szerint adódik át a fogadó függvény megkapja a referenciát, ami az átadott paraméter értékére mutat. Az adat módosítása a hívó függvénybeli értéket is megváltoztatja.

Függvény visszatérési értékek

Mint korábban említettük, a függvénynek lehet (de nem kötelező) visszatérési értéke.

A return utasítás

Függvényből való visszatérésre használjuk. Visszaadja a vezérlést a hívó függvénynek. A végrehajtás a hívás után folytatódik. Ha a függvénynek van visszatérési érte, szerepelnie kell benne a return utasításnak.

A return utasításban szerepelhet kifejezés, ennek értéke lesz a függvény visszetérési értéke. A kifejezés értékének azonos típusúnak kell lennie a deklarációban szereplő visszatérési típussal.

Példa: a fenti példák egyikében szereplő sqr függvény return utasítást használ az paraméterként átadott szám négyzetével való visszatéréshez:

sqr(n: int): int { return n*n; }

Modulok


A modul típus név egy azonosító.

modul-típus: azonosító

Az azonosítót modul azonosítóként deklaráljuk a modul deklarációban, ami magába foglalja az ADT-k, függvények, konstansok és beépített típusok deklarációit. A modul típusú objektum a modul kezelésére szolgál, és a modul függvényeinek elérésére használjuk.
A modul deklarációja után az azonosító a modul típusának neve lesz.
Példa:
Linear: module { setflags: fn (flag: int); TRUNCATE: con 1; Vector: adt { v: array of real; add: fn (v1: self Vector, v2: Vector): Vector; cross: fn (v1: self Vector, v2: Vector): Vector; dot: fn (v1: self Vector, v2: Vector); make: fn (a: array of real): Vector; }; Matrix: adt { m: array of array of real; add: fn (m1: self Matrix, m2: Matrix): Matrix; mul: fn (m1: self Matrix, m2: Matrix): Matrix; make: fn (a: array of array of real): Matrix; }; };

A fenti kódrészlet egy lineáris algebrai csomag modul deklarációja, mely két ADT-t implementál (Vector és Matrix), szerepel benne egy konstans, és a setflags függvény. A Linear név a modul típus neve, és a modul egy példányának deklarálására használható:

linearmodule: Linear;

Mielőtt a modult használni tudnánk, be kell tölteni, például a következő módon:

linearmodule = load Linear "/usr/dmr/limbo/linear.dis"; if (linearmodule == nil) { sys->print("Can't load Linear\n"); exit; }

A modul deklarációban deklarált adatok inicializálása a legfelső szinten egy értékadó utasítással történik. Például:

implement testmod; testmod: module { num: int; }; . . . num = 5;

Az értékadás jobb oldalán konstans kifejezésnek kell szerepelnie.


A load operátor

A load kifejezés általános alakja:

load-kifejezés: load azonosító kifejezés

Az azonosító a modul azonosítója (a module deklarációban deklarált típus neve). A load utáni kifejezés sztring típusú, a modul lefordított alakját tartalmazó fálj neve.
A load futtatása során a modult tartalmazó fájl bekerül a helyi memóriába, és dinamikusan típuselleneőrzést végez az interfészen: a futás idejű rendszer kideríti, hogy a modul által exportált deklarációk kompatibilisek-e a load operátor érvényességi tartományában szereplő modul deklarációval.

Ha a betöltési kísérlet meghiúsul, a load értéke nil lesz. A kísérlet meghiúsulhat, ha a modult tartalmazó fájl nem található meg, vagy ha a megtalált modul nem exportálja a kívánt felületet.

A load minden kiértékelése során a megnevezett modul egy új példánya jön létre, mely nem osztozik adatain a többi példánnyal.