require "python-semantics-calls.k" module PYTHON-SEMANTICS-GENERATOR imports PYTHON-SEMANTICS-CALLS rule [invoke-generator-function]: invoke(obj(_:Int,... "__closure__" |-> Closure "__code__" |-> ref(Code) "__globals__" |-> Globals ...), M) ~> K:K => makeFrame(N, ref(Code), ref("None"), makeLocals(ref(Code) . String2Id("co_freevars"), Closure), Globals, Globals["__builtins__"], makeCells(ref(Code) . String2Id("co_freevars"), ref(Code) . String2Id("co_cellvars"), Closure, N), M) ~> mutable("gi_code" |-> ref(Code) "gi_frame" |-> ref(N) "gi_running" |-> ref("False") "gi_state" |-> .K, ref("generator")) ... N => N +Int 1 ... Code ... "co_flags" |-> Flags ... ... when Flags &Int 32 =/=Int 0 [allocation] rule invokeBuiltin(obj("iter_generator",_), ListItem(O), .) => O rule invokeBuiltin(obj("next_generator",_), ListItem(O), .) => runGenerator(ref(id(O)), ref("None")) rule invokeBuiltin(obj("send_generator",_), ListItem(O) ListItem(O2), .) => runGenerator(ref(id(O)), O2) rule invokeBuiltin(obj("throw_generator",_), ListItem(O) ListItem(Type), .) => ref("throw_generator")(O, Type, ref("None"), ref("None")) rule invokeBuiltin(obj("throw_generator",_), ListItem(O) ListItem(Type) ListItem(Value), .) => ref("throw_generator")(O, Type, Value, ref("None")) rule invokeBuiltin(obj("throw_generator",_), ListItem(O) ListItem(Type) ListItem(Value) ListItem(Traceback), .) => test(or(istype(Traceback, ref("NoneType")), istype(Traceback, ref("traceback"))), test(or(istype(Type, ref("BaseException")), hasbase(Type, ref("BaseException"))), test(and(istype(Type, ref("BaseException")), negate(istype(Value, ref("NoneType")))), raiseInternal("TypeError", "instance exception may not have a separate value"), createRaiseStatement(O, Type, .Obj if Value is ref("None") else Value, .Obj if Traceback is ref("None") else Traceback)), raiseInternal("TypeError", "exceptions must be classes or instances deriving from BaseException")), raiseInternal("TypeError", "throw() third argument must be a traceback object")) syntax ObjRef ::= createRaiseStatement(Exp, Exp, Exp, Exp) [strict] rule createRaiseStatement(O, Type, .Obj, .Obj) => throwGenerator(ref(id(O)), test(istype(Type, ref("BaseException")), Type, Type(.Arguments))) rule createRaiseStatement(O, Type, Value:Object, .Obj) => throwGenerator(ref(id(O)), Type(Value)) rule createRaiseStatement(O, Type, .Obj, Traceback:Object) => test(istype(Type, ref("BaseException")), throwGenerator(ref(id(O)), Type . String2Id("with_traceback")(Traceback)), throwGenerator(ref(id(O)), Type(.Arguments) . String2Id("with_traceback")(Traceback))) rule createRaiseStatement(O, Type, Value:Object, Traceback:Object) => throwGenerator(ref(id(O)), Type(Value) . String2Id("with_traceback")(Traceback)) rule invokeBuiltin(obj("close_generator",_), ListItem(O), .) => try: throwGenerator(ref(id(O)), ref("GeneratorExit")) ; except ref("GeneratorExit") : ref("None") except ref("StopIteration") : ref("None") else: raiseInternal("RuntimeError", "generator ignored GeneratorExit") syntax ObjRef ::= runGenerator(Exp, Exp) [seqstrict(2, 1)] | throwGenerator(Exp, Exp) [seqstrict(2, 1)] | enterGenerator(Exp, K, K) rule runGenerator(O:Object, Arg:Object) => if Arg is not ref("None") : raiseInternal("TypeError", "can't send non-None value to just-started generator") else: enterGenerator(O, .K, .K) when getattr(O, "gi_state") ==K .K rule throwGenerator(O:Object, Ex:Object) => enterGenerator(O, raise Ex, getattr(O, "gi_state")) rule runGenerator(O:Object, Arg:Object) => enterGenerator(O, Arg, getattr(O, "gi_state")) when getattr(O, "gi_state") =/=K .K syntax K ::= beginRunningGenerator(Object) rule beginRunningGenerator(O) => if getref(O, "gi_running"): raiseInternal("ValueError", "generator already executing") ~> setref(id(O), "gi_running", ref("True")) rule [start-generator]: enterGenerator(O, Val, .K) ~> K => beginRunningGenerator(O) ~> Val ~> getattr2(getref(O, "gi_code"), "co_code") ~> return ... Frame => id(getattr(O, "gi_frame")) FL => . XC (C:Bag => .List .List ) . => ListItem(generator(Frame, C, FL, XC, K, ref(id(O)))) ... ... syntax K ::= (K, CurrentFrameCellFragment, List, K) rule [continue-generator]: enterGenerator(O, Val, (RestoredK, RestoredC, RestoredFL, RestoredXC)) ~> K => beginRunningGenerator(O) ~> Val ~> RestoredK ~> return ... Frame => id(getattr(O, "gi_frame")) FL => RestoredFL XC => RestoredXC (C:Bag => RestoredC) . => ListItem(generator(Frame, C, FL, XC, K, ref(id(O)))) ... ... syntax Arguments ::= "#if" Bool "#then" Arguments "#else" Arguments "#fi" [function] rule return O:Object ~> _ => setref(N, "gi_running", ref("False")) ~> setattr(N, "gi_state", (#freezer (HOLE ;)(.KList), SavedC, .List, SavedXC)) ~> raise ref("StopIteration")(#if id(O) ==K NoneId #then .Arguments #else O #fi) ~> K ... ListItem(generator(Frame, C, FL, XC, K, ref(N))) => . ... _ => Frame . => FL SavedXC => XC (SavedC => C) ... ... "None" |-> NoneId ... rule [yield]: yield O ~> SavedK => setref(N, "gi_running", ref("False")) ~> setattr(N, "gi_state", (SavedK, SavedC, SavedFL, SavedXC)) ~> O ~> K ... ListItem(generator(Frame, C, FL, XC, K, ref(N))) => . ... _ => Frame SavedFL => FL SavedXC => XC (SavedC => C) rule [raise-out-of-generator]: (. => setref(N, "gi_running", ref("False")) ~> setattr(N, "gi_state", (#freezer (HOLE ;)(.KList), . SavedC, .List, ref("None")))) ~> raise ... ... ListItem(generator(Frame, C, FL, _, _, ref(N))) => . ... ( . SavedC => C) _ => Frame . => FL SavedXC ... endmodule