A TOM programozási nyelv

Kivételek

Kivételek létrehozása és kiértékelése a tom unitban definiált objektumokon keresztül történik:
Condition objektumok előidézhetők vagy jelölhetők, és bármilyen objektum dobható (throw).

A kivételkezelés (szemben a létrehozással) része a nyelvnek. Erre a célra a TOM néhány speciális kifejezést biztosít:

condition_expression: catch_expression | bind_expression | unwind_expression ;

catch

A catch segítségével tudjuk az eldobott kivételeket elkapni. Felépítése a következő:

catch_expression: catch '(' tag ')' expression;

catch egy visszatérési pontot létesít egy throw hívási vermében. Egy throw egy meghívása a tag throw metódusának.

tag: expression ;

A throw alapértelmezett implementációja okozza a program futásának folytatását ugyanannak a tag objektumnak a leggyakrabban létesülő catch-e után. Nyilvánvalóan, mivel throw egy metódus, felül lehet írni. Ezzel vigyázni kell, mivel az alapértelmezett szemantika garantálja, hogy a throw hívásából nincs return.

Normálisan a catch által visszaadott érték az expression értéke. Ha egy catch dobódott, a visszatérési érték throw–nak való argumentum értéke. Ha a throw argumentuma void, a catch egyszerűen az alapértelmezett értékeit adja vissza azoknak az elemeknek, amiket egyébként visszaadna. Ha a throw–nak void–tól különböző argumentumai vannak, hibát jelent, ha a dobott típus nem egyezik meg az elkapottal.

bind

A bind segítségével tudunk kivétel kezelőket definiálni. A felépítése a következő:

bind_expression: bind '(' handlers ')' expression ; handlers: handler [';' handlers] ;

Egy bind_expression beállít egy vagy több kezelőt (handler) minden kivételre, ami kiváltva vagy jelölve lett az expression kiértékélése közben. A bind visszatérési értéke az az érték, amivel az expression visszatér.

handler: '(' condition ',' expression ')'; condition: expression ;

Minden handler egy expression, ami akkor hívódik meg, ha a condition, vagy egy alkivétel kiváltódik (vagy jelölődik).

Egy hasznos dolog a kezelő számára, hogy bizosítson egy throw-t hogy lehetővé tegye a nem-lokális visszatérést a kivételes állapotból. Figyelembe kell venni, hogy a kezelő meghívása a kiváltott kivétel környezetében történik.

catch (self) bind ((error, {[self throw void]; nil;})) { do_something_difficult; }

A throw–nak szüksége van azonnali return-re ebből a catch-ből, hacsak ugyanannak a self objektumnak egy másik catch-e nincs beállítva (és aktív) a do_something_difficult hívása alatt.

A kezelőnek nem szükséges úgy kezelni a kivételt, hogy egy nem-lokális visszatérést biztosít. Ha a kezelő nem akarja lekezelni, a kezelő által visszaadott értéknek ugyanannak a condition objektumnak kell lennie, amit kapott. Ha a kezelő bármilyen más értéket ad vissza, aminek mindig egy objektumnak kell lennie, a kezelő kezeltnek ítéli a kivételt. Ha a kivétel jelölve volt, a kezelő által visszaadott érték a signal által visszaadott érték. Ha kivétel volt kiváltva, a visszatérési érték figyelmen kívül lesz hagyva és a kivételkezelés folytatódik, mintha a kezelő nem kezelte volna a kivételt.

unwind

Az unwind segítségével tudunk az illetéktelen throw-ok ellen védekezni. A felépítése a következő:

unwind_expression: unwind '(' protection ')' body ; protection: expression ;

Egy unwind kiértékeli a body–t, amit a protection kiértékelése követ. Az unwind által visszaadott érték a törzsének az értéke.

Ha a törzs kiértékelése közben, egy tag dobódik, korán kilépve ezzel az unwind környezetéből, a protection kifejezés még mindig kiértékelődik. Ha a kód nem vált ki kivételt vagy dob bármit, akkor lefutása után az eredeti throw általi meghívás folytatódik tovább.