From f4ea799d42f8fc924fdaf5a58c0bef20471091ac Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Wed, 31 Mar 2021 19:06:33 +0900 Subject: [PATCH] Fix generator not being popped from stack on 'yield from' --- src/vm.c | 9 ++++- test/testYieldFromEventLoop.krk | 47 ++++++++++++++++++++++++++ test/testYieldFromEventLoop.krk.expect | 15 ++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 test/testYieldFromEventLoop.krk create mode 100644 test/testYieldFromEventLoop.krk.expect diff --git a/src/vm.c b/src/vm.c index a6b403f..c7fdc53 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2456,12 +2456,19 @@ _finishReturn: (void)0; krk_push(krk_peek(0)); krk_push(krk_callSimple(krk_peek(0),0,0)); } - if (!krk_valuesSame(krk_peek(0), krk_peek(1))) break; + if (!krk_valuesSame(krk_peek(0), krk_peek(1))) { + /* Value to yield */ + break; + } + + krk_pop(); /* Does it have a final value? */ method = krk_valueGetAttribute_default(krk_peek(0), "__finish__", NONE_VAL()); if (!IS_NONE(method)) { krk_push(method); + krk_swap(1); + krk_pop(); krk_push(krk_callSimple(krk_peek(0),0,0)); } else { krk_pop(); diff --git a/test/testYieldFromEventLoop.krk b/test/testYieldFromEventLoop.krk new file mode 100644 index 0000000..a76273f --- /dev/null +++ b/test/testYieldFromEventLoop.krk @@ -0,0 +1,47 @@ + +if not hasattr(__builtins__,'StopIteration'): + class StopIteration(Exception): + pass + __builtins__.StopIteration = StopIteration + +class Awaiter: + def __iter__(self): + yield " Awaiter(): awaitable returns an iterator" + return "(all done)" + +def foo(i,result=None): + print(' foo(): hi') + result = yield from i() + print(' Awaiting result 1:', result) + result = yield from Awaiter() + print(' Awaiting result 2:', result) + result = yield from i() + print(' Awaiting result 3:', result) + print(' foo(): bi') + return "done" + +def bar(): + print(" bar(): hello, there, I'm an async function") + return 42 + yield 0xdeadbeef + +def run(coro, scheduled=None, next=None, result=None): + # Okay, let's see. + scheduled = [coro] + print("Starting run loop.") + while scheduled: + print(" Popping from scheduled list.") + next = scheduled.pop(0) # Yes, that's slow, I know. + try: + print(" Calling",type(next)) + result = next.send(None) + if result == next: + raise StopIteration(result.__finish__()) + print(" Returned with",result) + scheduled.append(next) + except StopIteration as e: + # Stop iteration value should be return value from foo() + print('Exception:', type(e), e) + print('Done with run loop.') + +run(foo(bar)) diff --git a/test/testYieldFromEventLoop.krk.expect b/test/testYieldFromEventLoop.krk.expect new file mode 100644 index 0000000..25a55cf --- /dev/null +++ b/test/testYieldFromEventLoop.krk.expect @@ -0,0 +1,15 @@ +Starting run loop. + Popping from scheduled list. + Calling + foo(): hi + bar(): hello, there, I'm an async function + Awaiting result 1: 42 + Returned with Awaiter(): awaitable returns an iterator + Popping from scheduled list. + Calling + Awaiting result 2: (all done) + bar(): hello, there, I'm an async function + Awaiting result 3: 42 + foo(): bi +Exception: done +Done with run loop.