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)) => . ... ... ... B ... "__traceback__" |-> Tb ... ... 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) ... B OAttrs:Map => OAttrs[B2 / "__context__"] ... rule savetb(O:Object) => setref(B, "__traceback__", O) ... ref(B) rule setx(Ex) => . ... _ => Ex rule setcause(obj(B,_), obj(B2,_)) => . ... ... B OAttrs => OAttrs[ref(B2) / "__cause__"] ... //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