require "python-semantics-common.k"
module PYTHON-SEMANTICS-TRY
imports PYTHON-SEMANTICS-COMMON
syntax K ::= try(K, K, CurrentFrameCellFragment, K, Bool)
syntax K ::= savex(Exp) [strict]
| setcause(Exp, Exp) [strict]
| doExcept(Exp, K, NAME) [strict(1)]
| doExcepts(List, K, NAME)
| doRaise(Exp, Exp, Bool) [strict(1, 2)]
| "popfinally"
rule (try: Try:K ECs:K else: Else:K => Try ~> popx ~> Else) ~> K:K
. => ListItem(try(ECs, K, C, Ex, true)) ...
Ex
C:Bag
rule (try: Try finally: Finally:K => Try ~> popfinally ~> Finally) ~> K
(. => ListItem(finally(Finally ~> raise, C, XL, LL, FL, Ex))) XL:List
(. => ListItem(finally(Finally, C, XL, LL, FL, Ex))) LL:List
(. => ListItem(finally(Finally, C, XL, LL, FL, Ex))) FL:List
Ex
C:Bag
rule popfinally => . ...
_:ListItem => . ...
_:ListItem => . ...
_:ListItem => . ...
rule popx => . ...
_:ListItem => . ...
rule raise => raise ref("RuntimeError")("No active exception to reraise") ...
ref("None")
rule (. => ECs) ~> raise ...
B
ListItem(try(ECs, _, C, _, (true => false))) ...
(_ => C)
when B =/=K ref("None")
rule raise ~> _ => Finally
B
ListItem(finally(Finally, C, _, LL, FL, _)) => . ...
_ => LL
_ => FL
(_ => C:Bag)
when B =/=K ref("None")
rule (. => savetb(mutable("tb_next" |-> Tb "tb_frame" |-> ref(Frame), ref("traceback")))) ~> raise ...
...
ref(B)
Frame
ListItem(try(_, _, _:Bag, _, false)) => . ...
...
when B =/=K "None"
rule raise ...
...
ListItem(call(Frame, C, FL, _, _)) => . ...
( .
_ => C)
_ => Frame
_ => FL
_
...
rule (EC)::ExceptClause (ECs)::ExceptClauses => EC ~> ECs ... when notBool(getKLabel EC ==KLabel 'except:_ andBool ECs =/=K .ExceptClauses)
rule .ExceptClauses => . ...
rule raise O:Object => doRaise(test(istype(O, ref("type")), O(.Arguments), O), ref("None"), true) ...
rule raise O:Object from O2:Object => doRaise(test(istype(O, ref("type")), O(.Arguments), O), test(istype(O2, ref("type")), O2(.Arguments), O2), false) ...
rule doRaise(O, O2, T:Bool) => test(istype(O, ref("BaseException")), test(or(id(O2) ==K NoneId,istype(O2, ref("BaseException"))), (setcause(O, O2) ~> setref(id(O), "__suppress_context__", test(T, ref("False"), test(id(O2) ==K NoneId, ref("True"), ref("False")))) ~> savex(O) ~> savetb(mutable("tb_next" |-> ref("None") "tb_frame" |-> ref(Frame), ref("traceback"))) ~> raise) , raiseInternal("TypeError", "exception causes must derive from BaseException")), raiseInternal("TypeError", "exceptions must derive from BaseException")) ...
Frame
... "None" |-> NoneId ...
rule savex(obj(B,_)) => . ...
B2 => ref(B)
rule savetb(O:Object) => setref(B, "__traceback__", O) ...
ref(B)
rule setx(Ex) => . ...
_ => Ex
rule setcause(obj(B,_), obj(B2,_)) => . ...
//TODO: handle traceback line numbers
rule except: Except:K ~> _ => Except ~> setx(Ex) ~> K
...
ListItem(try(_, K, _:Bag, Ex, false)) => . ...
...
rule except O : Except => except O as String2Id(""): Except
rule except O:Object as X:NAME : Except:K => test(hasbase(O, ref("BaseException")), doExcept(O, Except, X), test(istype(O, ref("tuple")), doExcepts(listvalue(O), Except, X), raiseInternal("TypeError", "catching classes that do not inherit from BaseException is not allowed"))) ...
rule doExcepts(., Except, X) => . ...
rule doExcepts(ListItem(B) L:List, Except, X) => doExcept(B, Except, X) ~> doExcepts(L, Except, X) ...
rule doExcept(Type:Object, Except, X) => test(istype(B, Type), test(Id2String(X) ==String "", except: Except, ((X:Id)::Target = B ~> except: (try: Except finally: try: unbind(X) except ref("NameError"): pass))), .) ...
B:Exp
rule invokeBuiltin(obj("sys_exc_info",_), ., .) => tuple(#if Ex ==K ref("None") #then ref("None") #else Ex . String2Id("__class__") #fi, Ex, #if Ex ==K ref("None")
#then ref("None") #else Ex . String2Id("__traceback__") #fi) ...
Ex:Exp
endmodule