This is a simple implementation of Java try/catch/finally, translated in Try/Failure/Finally
(* Mathematica Package *)
BeginPackage["Language`"]
(* ----------------------------------------------------------------------- *)
(*
Try/Failure/Finally
Failed/$Return/$Failure
Try[
body,
Failure[form, cbody],
...
Finally[fbody]
]
where
Failed[tag] == Throw[$Failed, tag]
Failed[c::m, args___] == Throw[$Failed, Hold[c::m, {args}]]
It is possible modify the result generated in 'body' by assign a new
value to the symbol '$return'.
With 'Throw[result, tag]', the result of the expression is 'result'
(o '$Failed' if you use 'Failed[tag]').
The value 'result' will be assigned to '$Return'
Try[] == Try[Null]
Try[body, Failure[...]*, Finally[...]?]
Failure[] == Failure[_, Null]
Failure[form] == Failure[form, Null]
Failure[form, ebody]
Finally[] == Finally[Null]
Finally[fbody]
form: a pattern
tag: a expression
body, ebody, fbody: a expression
La valutazione procede come segue:
1) viene valutato 'body' (Try[body, ...])
2) se non ci sono eccezioni, il risultato viene assegnato a $Return
3) se e' presente la sezione 'Finally[fbody]' viene valutato 'fbody'
4) - se in 'fbody' non viene assegnato un nuovo valore a '$Return' e ritorna
Null, allora il risultato e' il corrente valore di $Return
- se in 'fbody' viene assegnato un nuovo valore a '$Return' e ritorna
Null, allora il risultato e' il nuovo valore di $Return
- se 'fbody' ritorna un valore diverso da Null, allora questo e' il nuovo
valore dell'espressione
5) in caso di eccezione (generata con 'Throw[value, tag]' oppure 'Failure[tag]'
che e' equivalente a 'Throw[$Failed, tag]'), il valore di '$Return' e'
'value' o '$Failed'.
6) vengono scandite le sezioni 'Failure[form, cbody]' alla ricerca della
prima in cui 'form' ha un match con 'tag':
- se non viene trovata, l'eccezione viene propagata ma VIENE valutata la
sezione 'Finally[fbody]' se presente
- se viene trovata, viene valutato 'cbody', che segue le stesse regole
di 'fbody'
- se e' presente la sezione 'Finally[fbody]' la valutazione procede
come indicato al punto 4
7) l'esatta eccezione sollevata (tag) si puo' trovare nei blocchi 'Failure[]'
e 'Finally[]' nella variabile '$Failure'
Le variabili '$Failure' e '$Return' usano 'dynamic scoping' ('Block[...]')
In 'ebody' e' possibile utilizzare eventuali pattern definiti in 'form'
*)
(* ----------------------------------------------------------------------- *)
$Return::usage="Usable in 'body' on 'Failure[]' and 'Finally[]' to change the \
return value, but 'body' MUST return 'Null'. Otherwise the new value returned \
is the value of the body evaluation";
$Failure::usage="Contains the exception generated";
Try::usage="Try[body, Failure[form, ebody]*, Finally[fbody]?] execute 'body' and \
'fbody' if present.
If 'body' generate a exception (using Throw[.., tag]) the next expression \
evaluated is the first 'ebody' of the 'Failure[form, ebody]' list where 'form' \
match 'tag'";
Failed::usage="Failed[tag] == Throw[$Failed, tag]\
Failed[c::m, args___] === Throw[$Failed, Hold[c::m, {args}]]";
Failure::usage="Failure[tag, ebody] | Failure[tag] | Failure[]"
Finally::usage="Finally[fbody] | Finally[]";
(* ----------------------------------------------------------------------- *)
(* *)
(* ----------------------------------------------------------------------- *)
Begin["`Private`"]
Unprotect[
Try, Failure, Finally,
Failed, $Return, $Failure
];
(* ----------------------------------------------------------------------- *)
(*
Try[] == Try[Null]
Try[body, Failure[...]*, Finally[...]?]
Failure[] == Failure[_, Null]
Failure[form] == Failure[form, Null]
Failure[form, ebody]
Finally[] == Finally[Null]
Finally[fbody]
form: un pattern
tag: un'espressione
*)
(* ----------------------------------------------------------------------- *)
SetAttributes[Try, HoldAll];
SetAttributes[Failed, HoldFirst];
SetAttributes[HandleFailures, HoldAll];
(* ----------------------------------------------------------------------- *)
(* Failed *)
(* ----------------------------------------------------------------------- *)
Failed[fail_] := Throw[$Failed, Evaluate[fail]];
Failed[message:MessageName[category_, _], args___] :=
With[{mh = Hold[message, {args}]},
Message[message, args];
Throw[$Failed, mh];
];
(* ----------------------------------------------------------------------- *)
(* Try *)
(* ----------------------------------------------------------------------- *)
Try[body_:Null, Longest[failures___Failure], finally_Finally:Finally[]] :=
Block[{$Return=Null, $Failure=Null},
Catch[
HandleBody[body],
_,
HandleFailures[#1, #2, Hold[failures]]&
];
HandleFinally[finally];
Return[$Return];
];
(* ----------------------------------------------------------------------- *)
(* HandleBody *)
(* ----------------------------------------------------------------------- *)
HandleBody[body_] :=
With[{},
$Return=Evaluate[body]
];
(* ----------------------------------------------------------------------- *)
(* HandleFailures *)
(* ----------------------------------------------------------------------- *)
(*
Param failures: Hold[failure, ...]
failure ::= Failure[] == Failure[_, Null]
Failure[form] == Failure[form, Null]
Failure[form, body]
*)
HandleFailures[return_, tag_, failures_]:=
Module[{i, n=Length[failures]},
$Return=return;
$Failure=tag;
For[i=1, i<=n, ++i,
With[{failure=failures[[i]]},
If[Length[failure]==0, Return[$Return]]; (*Failure[]*)
With[{form=failure[[1]]}, (*Failure[form, body?]*)
If[MatchQ[tag, form],
Return[HandleFailure[tag, failure]];
]]];
];
Throw[return, tag];
];
(*
Failure[form] == Failure[form, Null]
Failure[form, body]
*)
HandleFailure[tag_, Failure[form_, body_:Null]] :=
With[{return=tag/.form->body},
If[return =!= Null, $Return=return];
Return[$Return];
];
(* ----------------------------------------------------------------------- *)
(* HandleFinally *)
(* ----------------------------------------------------------------------- *)
(*
Finally[] == Finally[Null]
Finally[body]
*)
HandleFinally[Finally[body_:Null]] :=
With[{return=Evaluate[body]},
If[return =!= Null, $Return=return];
Return[$Return];
];
(* ----------------------------------------------------------------------- *)
(* *)
(* ----------------------------------------------------------------------- *)
Protect[
Try, Failure, Finally,
Failed, $Failure, $Return
];
End[]
Print["Language`TryCatch` Installed"]
EndPackage[]