Browse Source

Improve backwards-compat for execute_yields

jonathanvdc 8 years ago
parent
commit
91b359cd51
1 changed files with 47 additions and 36 deletions
  1. 47 36
      kernel/modelverse_kernel/main.py

+ 47 - 36
kernel/modelverse_kernel/main.py

@@ -34,43 +34,54 @@ def pop_requests(requests, opStack):
         set_finished_requests_flag(opStack)
         return requests
 
-    first_request = requests.pop(0)
-    if first_request[0] == "RUN":
-        # The kernel handles RUN-requests.
-        if len(requests) == 0:
-            set_finished_requests_flag(opStack)
-
-        _, request_args = first_request
-        if len(request_args) == 1:
-            # Format: ("RUN", [gen])
-            gen, = request_args
-            push_generator(gen, opStack)
-        else:
-            # Format: ("RUN", [func, kwargs])
-            # This format is useful because it also works for functions that
-            # throw an exception but never yield.
-            func, kwargs = request_args
-            # We need to be extra careful here, because func(**kwargs) might
-            # not be a generator at all: it might simply be a method that
-            # raises an exception. To cope with this we need to push a dummy
-            # entry onto the stack if a StopIteration or PrimtiveFinished
-            # exception is thrown. The logic in execute_yields will then pop
-            # that dummy entry.
-            try:
-                push_generator(func(**kwargs), opStack)
+    for i, elem in enumerate(requests):
+        if elem[0] == "RUN":
+            # The kernel should handle RUN-requests.
+            if i > 0:
+                # Handle any requests that precede the RUN-request first.
+                pre_requests = requests[:i]
+                del requests[:i]
+                return pre_requests
+
+            # The RUN-request must be the first element in the list. Pop it.
+            requests.pop(0)
+
+            # The list of requests might be empty now. If so, then flag this
+            # batch of requests as finished.
+            if len(requests) == 0:
+                set_finished_requests_flag(opStack)
+
+            _, request_args = elem
+            if len(request_args) == 1:
+                # Format: ("RUN", [gen])
+                gen, = request_args
+                push_generator(gen, opStack)
                 raise RunRequest()
-            except StopIteration:
-                push_generator(None, opStack)
-                raise
-            except primitive_functions.PrimitiveFinished as ex:
-                push_generator(None, opStack)
-                raise
-    else:
-        # The state handles all other requests.
-        if len(requests) == 0:
-            set_finished_requests_flag(opStack)
-
-        return [first_request]
+            else:
+                # Format: ("RUN", [func, kwargs])
+                # This format is useful because it also works for functions that
+                # throw an exception but never yield.
+                func, kwargs = request_args
+                # We need to be extra careful here, because func(**kwargs) might
+                # not be a generator at all: it might simply be a method that
+                # raises an exception. To cope with this we need to push a dummy
+                # entry onto the stack if a StopIteration or PrimtiveFinished
+                # exception is thrown. The logic in execute_yields will then pop
+                # that dummy entry.
+                try:
+                    push_generator(func(**kwargs), opStack)
+                    raise RunRequest()
+                except StopIteration:
+                    push_generator(None, opStack)
+                    raise
+                except primitive_functions.PrimitiveFinished as ex:
+                    push_generator(None, opStack)
+                    raise
+
+    # We couldn't find a RUN-request in the batch of requests, so we might as well
+    # handle them all at once then.
+    set_finished_requests_flag(opStack)
+    return requests
 
 class ModelverseKernel(object):
     def __init__(self, root):