primitives.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. import time as python_time
  2. class PrimitiveFinished(Exception):
  3. """Exception to indicate the result value of a primitive, as a return cannot be used."""
  4. def __init__(self, value):
  5. Exception.__init__(self)
  6. self.result = value
  7. class InterpretedFunctionFinished(Exception):
  8. """Exception to indicate the result value of an interpreted function, as a return
  9. cannot be used."""
  10. def __init__(self, value):
  11. Exception.__init__(self)
  12. self.result = value
  13. class SleepKernel(Exception):
  14. """Exception to indicate the kernel to sleep for some time."""
  15. def __init__(self, timeout, interruptable):
  16. Exception.__init__(self)
  17. self.timeout = timeout
  18. self.interruptable = interruptable
  19. # Functions annotated with __exception_return use the JIT's calling convention instead of
  20. # the kernel's: returns are handled by throwing a PrimitiveFinished exception; the caller's
  21. # returnvalue is not modified.
  22. #
  23. # ### Rationale for __exception_return
  24. #
  25. # __exception_return is a useful mechanism because it allows us to have a __call_function
  26. # implementation that has O(1) state read overhead. A previous implementation of
  27. # __call_function checked if the caller's frame had been popped whenever
  28. # ModelverseKernel.execute_yield threw a StopIteration exception. However, that incurs O(n) overhead
  29. # _per call,_ where n is the number of StopIteration exceptions that are thrown during the call.
  30. # O(n) is pretty bad, but this actually becomes O(n * m) when m calls to __call_function are
  31. # nested. And that's just not acceptable.
  32. # __exception_return requires kernel support, but I think the complexity gains are well worth it;
  33. # I reckon JIT-to-interpreter switches aren't going to get a whole lot cheaper than this.
  34. EXCEPTION_RETURN_KEY = "__exception_return"
  35. """A dictionary key for functions which request that the kernel throw a InterpretedFunctionFinished
  36. exception with the return value instead of injecting the return value in the caller's frame."""
  37. def integer_subtraction(a, b, **remainder):
  38. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  39. result, = yield [("CNV", [a_value - b_value])]
  40. raise PrimitiveFinished(result)
  41. def integer_addition(a, b, **remainder):
  42. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  43. result, = yield [("CNV", [a_value + b_value])]
  44. raise PrimitiveFinished(result)
  45. def integer_multiplication(a, b, **remainder):
  46. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  47. result, = yield [("CNV", [a_value * b_value])]
  48. raise PrimitiveFinished(result)
  49. def integer_division(a, b, **remainder):
  50. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  51. result, = yield [("CNV", [int(a_value) / b_value])]
  52. raise PrimitiveFinished(result)
  53. """
  54. def integer_gt(a, b, **remainder):
  55. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  56. result, = yield [("CNV", [a_value > b_value])]
  57. raise PrimitiveFinished(result)
  58. """
  59. def integer_lt(a, b, **remainder):
  60. # TODO make non-primitive, though compiled
  61. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  62. result, = yield [("CNV", [a_value < b_value])]
  63. raise PrimitiveFinished(result)
  64. """
  65. def integer_neg(a, **remainder):
  66. # TODO make non-primitive, though compiled
  67. a_value, = yield [("RV", [a])]
  68. result, = yield [("CNV", [-a_value])]
  69. raise PrimitiveFinished(result)
  70. """
  71. def bool_and(a, b, **remainder):
  72. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  73. result, = yield [("CNV", [a_value and b_value])]
  74. raise PrimitiveFinished(result)
  75. def bool_or(a, b, **remainder):
  76. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  77. result, = yield [("CNV", [a_value or b_value])]
  78. raise PrimitiveFinished(result)
  79. def bool_not(a, **remainder):
  80. a_value, = yield [("RV", [a])]
  81. result, = yield [("CNV", [not a_value])]
  82. raise PrimitiveFinished(result)
  83. def float_subtraction(a, b, **remainder):
  84. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  85. result, = yield [("CNV", [a_value - b_value])]
  86. raise PrimitiveFinished(result)
  87. def float_addition(a, b, **remainder):
  88. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  89. result, = yield [("CNV", [a_value + b_value])]
  90. raise PrimitiveFinished(result)
  91. def float_multiplication(a, b, **remainder):
  92. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  93. result, = yield [("CNV", [a_value * b_value])]
  94. raise PrimitiveFinished(result)
  95. def float_division(a, b, **remainder):
  96. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  97. result, = yield [("CNV", [float(a_value) / float(b_value)])]
  98. raise PrimitiveFinished(result)
  99. """
  100. def float_gt(a, b, **remainder):
  101. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  102. result, = yield [("CNV", [a_value > b_value])]
  103. raise PrimitiveFinished(result)
  104. """
  105. def float_lt(a, b, **remainder):
  106. # TODO make non-primitive, though compiled
  107. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  108. result, = yield [("CNV", [a_value < b_value])]
  109. raise PrimitiveFinished(result)
  110. """
  111. def float_neg(a, **remainder):
  112. # TODO make non-primitive, though compiled
  113. a_value, = yield [("RV", [a])]
  114. result, = yield [("CNV", [-a_value])]
  115. raise PrimitiveFinished(result)
  116. """
  117. def string_join(a, b, **remainder):
  118. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  119. result, = yield [("CNV", [str(a_value) + str(b_value)])]
  120. raise PrimitiveFinished(result)
  121. def string_split(a, b, **remainder):
  122. # TODO make non-primitive, though compiled
  123. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  124. result = a_value.split(b_value)
  125. elems = yield [("CN", [])] + [("CNV", [v]) for v in result]
  126. new_val = elems[0]
  127. yield [("CD", [new_val, i, v]) for i, v in enumerate(elems[1:])]
  128. raise PrimitiveFinished(new_val)
  129. def string_get(a, b, **remainder):
  130. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  131. result, = yield [("CNV", [a_value[b_value]])]
  132. raise PrimitiveFinished(result)
  133. def string_len(a, **remainder):
  134. a_value, = yield [("RV", [a])]
  135. result, = yield [("CNV", [len(a_value)])]
  136. raise PrimitiveFinished(result)
  137. def value_eq(a, b, **remainder):
  138. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  139. result, = yield [("CNV", [a_value == b_value])]
  140. raise PrimitiveFinished(result)
  141. """
  142. def value_neq(a, b, **remainder):
  143. # TODO make non-primitive, though compiled
  144. a_value, b_value = yield [("RV", [a]), ("RV", [b])]
  145. result, = yield [("CNV", [a_value != b_value])]
  146. raise PrimitiveFinished(result)
  147. """
  148. def element_eq(a, b, **remainder):
  149. result, = yield [("CNV", [a == b])]
  150. raise PrimitiveFinished(result)
  151. """
  152. def element_neq(a, b, **remainder):
  153. # TODO make non-primitive, though compiled
  154. result, = yield [("CNV", [a != b])]
  155. raise PrimitiveFinished(result)
  156. """
  157. def cast_a2s(a, **remainder):
  158. a_value, = yield [("RV", [a])]
  159. result, = yield [("CNV", [str(a_value["value"])])]
  160. raise PrimitiveFinished(result)
  161. def cast_i2f(a, **remainder):
  162. a_value, = yield [("RV", [a])]
  163. result, = yield [("CNV", [float(a_value)])]
  164. raise PrimitiveFinished(result)
  165. def cast_i2s(a, **remainder):
  166. a_value, = yield [("RV", [a])]
  167. result, = yield [("CNV", [str(a_value)])]
  168. raise PrimitiveFinished(result)
  169. def cast_i2b(a, **remainder):
  170. a_value, = yield [("RV", [a])]
  171. result, = yield [("CNV", [bool(a_value)])]
  172. raise PrimitiveFinished(result)
  173. def cast_f2i(a, **remainder):
  174. a_value, = yield [("RV", [a])]
  175. result, = yield [("CNV", [int(a_value)])]
  176. raise PrimitiveFinished(result)
  177. def cast_f2s(a, **remainder):
  178. a_value, = yield [("RV", [a])]
  179. result, = yield [("CNV", [str(a_value)])]
  180. raise PrimitiveFinished(result)
  181. def cast_f2b(a, **remainder):
  182. a_value, = yield [("RV", [a])]
  183. result, = yield [("CNV", [bool(a_value)])]
  184. raise PrimitiveFinished(result)
  185. def cast_s2i(a, **remainder):
  186. a_value, = yield [("RV", [a])]
  187. result, = yield [("CNV", [int(a_value)])]
  188. raise PrimitiveFinished(result)
  189. def cast_s2f(a, **remainder):
  190. a_value, = yield [("RV", [a])]
  191. result, = yield [("CNV", [float(a_value)])]
  192. raise PrimitiveFinished(result)
  193. def cast_s2b(a, **remainder):
  194. a_value, = yield [("RV", [a])]
  195. result, = yield [("CNV", [bool(a_value)])]
  196. raise PrimitiveFinished(result)
  197. def cast_b2i(a, **remainder):
  198. a_value, = yield [("RV", [a])]
  199. result, = yield [("CNV", [int(a_value)])]
  200. raise PrimitiveFinished(result)
  201. def cast_b2f(a, **remainder):
  202. a_value, = yield [("RV", [a])]
  203. result, = yield [("CNV", [float(a_value)])]
  204. raise PrimitiveFinished(result)
  205. def cast_b2s(a, **remainder):
  206. a_value, = yield [("RV", [a])]
  207. result, = yield [("CNV", [str(a_value)])]
  208. raise PrimitiveFinished(result)
  209. def cast_e2s(a, **remainder):
  210. a_value, = yield [("RV", [a])]
  211. result, = yield [("CNV", ["{ID: %s, value: %s}" % (a, a_value)])]
  212. raise PrimitiveFinished(result)
  213. def cast_v2s(a, **remainder):
  214. a_value, = yield [("RV", [a])]
  215. if isinstance(a_value, (str, unicode)):
  216. # String should be encoded to distinguish between 3 and "3"
  217. a_value = '"%s"' % a_value
  218. elif isinstance(a_value, dict):
  219. # Action or type
  220. a_value = a_value["value"]
  221. result, = yield [("CNV", ["%s" % (a_value)])]
  222. raise PrimitiveFinished(result)
  223. def cast_id2s(a, **remainder):
  224. result, = yield [("CNV", ["%s" % (a)])]
  225. raise PrimitiveFinished(result)
  226. """
  227. def list_append(a, b, **remainder):
  228. # TODO make non-primitive, though compiled
  229. a_outgoing, = yield [("RO", [a])]
  230. _ = yield [("CD", [a, len(a_outgoing), b])]
  231. raise PrimitiveFinished(a)
  232. """
  233. def list_insert(a, b, c, **remainder):
  234. # TODO make non-primitive, though compiled
  235. a_outgoing, c_value = yield [("RO", [a]), ("RV", [c])]
  236. links = yield [("RD", [a, i]) for i in range(c_value, len(a_outgoing))] + \
  237. [("RDE", [a, i]) for i in range(c_value, len(a_outgoing))]
  238. values = links[:len(links)/2]
  239. edges = links[len(links)/2:]
  240. yield [("CD", [a, c_value, b])] + \
  241. [("CD", [a, c_value + 1 + index, value]) for index, value in enumerate(values)] + \
  242. [("DE", [i]) for i in edges]
  243. raise PrimitiveFinished(a)
  244. def list_delete(a, b, **remainder):
  245. # TODO make non-primitive, though compiled
  246. a_outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
  247. links = yield [("RD", [a, i]) for i in range(b_value, len(a_outgoing))] + \
  248. [("RDE", [a, i]) for i in range(b_value, len(a_outgoing))]
  249. values = links[:len(links)/2]
  250. edges = links[len(links)/2:]
  251. yield [("CD", [a, b_value + index, value]) for index, value in enumerate(values[1:])] + \
  252. [("DE", [i]) for i in edges]
  253. raise PrimitiveFinished(a)
  254. """
  255. def list_read(a, b, **remainder):
  256. # TODO same as dictionary read
  257. b_value, = yield [("RV", [b])]
  258. result, = yield [("RD", [a, b_value])]
  259. if result is None:
  260. raise Exception("List read out of bounds: %s" % b_value)
  261. raise PrimitiveFinished(result)
  262. """
  263. """
  264. def list_len(a, **remainder):
  265. # TODO same as read_nr_out
  266. outgoings, = yield [("RO", [a])]
  267. result, = yield [("CNV", [len(outgoings)])]
  268. raise PrimitiveFinished(result)
  269. """
  270. """
  271. def dict_add(a, b, c, **remainder):
  272. new_edge, = yield [("CE", [a, c])]
  273. yield [("CE", [new_edge, b])]
  274. raise PrimitiveFinished(a)
  275. """
  276. def dict_add_fast(a, b, c, **remainder):
  277. # TODO deprecate, as dict_add is now also efficient
  278. v, = yield [("RV", [b])]
  279. yield [("CD", [a, v, c])]
  280. raise PrimitiveFinished(a)
  281. def dict_delete(a, b, **remainder):
  282. b_value, = yield [("RV", [b])]
  283. edge, = yield [("RDE", [a, b_value])]
  284. if edge is None:
  285. print("Failed dict_delete for value %s!" % b_value)
  286. keys, = yield [("RDK", [a])]
  287. keys = yield [("RV", [i]) for i in keys]
  288. print("Keys: " + str(keys))
  289. yield [("DE", [edge])]
  290. raise PrimitiveFinished(a)
  291. def dict_delete_node(a, b, **remainder):
  292. edge, = yield [("RDNE", [a, b])]
  293. if edge is None:
  294. print("Failed dict_delete_node!")
  295. yield [("DE", [edge])]
  296. raise PrimitiveFinished(a)
  297. def dict_read(a, b, **remainder):
  298. b_value, = yield [("RV", [b])]
  299. result, = yield [("RD", [a, b_value])]
  300. raise PrimitiveFinished(result)
  301. def dict_read_edge(a, b, **remainder):
  302. b_value, = yield [("RV", [b])]
  303. result, = yield [("RDE", [a, b_value])]
  304. raise PrimitiveFinished(result)
  305. def dict_read_node(a, b, **remainder):
  306. result, = yield [("RDN", [a, b])]
  307. raise PrimitiveFinished(result)
  308. def dict_in(a, b, **remainder):
  309. b_value, = yield [("RV", [b])]
  310. value, = yield [("RD", [a, b_value])]
  311. is_in = value is not None
  312. result, = yield [("CNV", [is_in])]
  313. raise PrimitiveFinished(result)
  314. def dict_in_node(a, b, **remainder):
  315. value, = yield [("RDN", [a, b])]
  316. result, = yield [("CNV", [value is not None])]
  317. raise PrimitiveFinished(result)
  318. """
  319. def dict_len(a, **remainder):
  320. # TODO same as read_nr_out
  321. outgoings, = yield [("RO", [a])]
  322. result, = yield [("CNV", [len(outgoings)])]
  323. raise PrimitiveFinished(result)
  324. """
  325. def dict_keys(a, **remainder):
  326. keys, result = yield [("RDK", [a]), ("CN", [])]
  327. yield [("CE", [result, v]) for v in keys]
  328. raise PrimitiveFinished(result)
  329. def is_physical_int(a, **remainder):
  330. t, = yield [("RV", [a])]
  331. result, = yield [("CNV", [isinstance(t, int) or isinstance(t, long)])]
  332. raise PrimitiveFinished(result)
  333. def is_physical_string(a, **remainder):
  334. t, = yield [("RV", [a])]
  335. result, = yield [("CNV", [isinstance(t, str) or isinstance(t, unicode)])]
  336. raise PrimitiveFinished(result)
  337. def is_physical_float(a, **remainder):
  338. t, = yield [("RV", [a])]
  339. result, = yield [("CNV", [isinstance(t, float)])]
  340. raise PrimitiveFinished(result)
  341. def is_physical_boolean(a, **remainder):
  342. t, = yield [("RV", [a])]
  343. result, = yield [("CNV", [isinstance(t, bool)])]
  344. raise PrimitiveFinished(result)
  345. def is_physical_action(a, **remainder):
  346. t, = yield [("RV", [a])]
  347. result, = yield [("CNV", [isinstance(t, dict) and t["value"] in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]])]
  348. raise PrimitiveFinished(result)
  349. def create_node(**remainder):
  350. result, = yield [("CN", [])]
  351. raise PrimitiveFinished(result)
  352. def create_edge(a, b, **remainder):
  353. result, = yield [("CE", [a, b])]
  354. raise PrimitiveFinished(result)
  355. def create_value(a, **remainder):
  356. a_value, = yield [("RV", [a])]
  357. result, = yield [("CNV", [a_value])]
  358. raise PrimitiveFinished(result)
  359. def read_nr_out(a, **remainder):
  360. outgoing, = yield [("RO", [a])]
  361. result, = yield [("CNV", [len(outgoing)])]
  362. raise PrimitiveFinished(result)
  363. def read_out(a, b, root, **remainder):
  364. outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
  365. raise PrimitiveFinished(sorted(outgoing)[b_value] if len(outgoing) > b_value else root)
  366. def read_nr_in(a, **remainder):
  367. incoming, = yield [("RI", [a])]
  368. result, = yield [("CNV", [len(incoming)])]
  369. raise PrimitiveFinished(result)
  370. def read_in(a, b, root, **remainder):
  371. incoming, b_value = yield [("RI", [a]), ("RV", [b])]
  372. raise PrimitiveFinished(sorted(incoming)[b_value] if len(incoming) > b_value else root)
  373. def read_edge_src(a, **remainder):
  374. result, = yield [("RE", [a])]
  375. raise PrimitiveFinished(result[0])
  376. def read_edge_dst(a, **remainder):
  377. result, = yield [("RE", [a])]
  378. raise PrimitiveFinished(result[1])
  379. def delete_element(a, **remainder):
  380. edge, = yield [("RE", [a])]
  381. if edge[0] is None:
  382. # Not an edge:
  383. yield [("DN", [a])]
  384. result, = yield [("CNV", [False])]
  385. raise PrimitiveFinished(result)
  386. else:
  387. yield [("DE", [a])]
  388. result, = yield [("CNV", [True])]
  389. raise PrimitiveFinished(result)
  390. def read_root(root, **remainder):
  391. raise PrimitiveFinished(root)
  392. """
  393. def set_add(a, b, **remainder):
  394. # TODO make non-primitive, though compiled
  395. #yield [("CE", [a, b])]
  396. #raise PrimitiveFinished(a)
  397. outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
  398. if outgoing:
  399. elements = yield [("RE", [i]) for i in outgoing]
  400. values = yield [("RV", [i[1]]) for i in elements]
  401. if b_value is not None and b_value in values:
  402. raise PrimitiveFinished(a)
  403. elif b_value is None and b in elements:
  404. raise PrimitiveFinished(a)
  405. else:
  406. yield [("CE", [a, b])]
  407. raise PrimitiveFinished(a)
  408. else:
  409. yield [("CE", [a, b])]
  410. raise PrimitiveFinished(a)
  411. """
  412. """
  413. def set_pop(a, **remainder):
  414. # TODO make non-primitive, though compiled
  415. outgoing, = yield [("RO", [a])]
  416. if outgoing:
  417. v, _ = yield [("RE", [outgoing[0]]), ("DE", [outgoing[0]])]
  418. raise PrimitiveFinished(v[1])
  419. else:
  420. print("Pop from empty set!")
  421. raise PrimitiveFinished(remainder["root"])
  422. """
  423. def set_remove(a, b, **remainder):
  424. outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
  425. elements = yield [("RE", [i]) for i in outgoing]
  426. values = yield [("RV", [i[1]]) for i in elements]
  427. yield [("DE", [identifier]) for identifier, edge in zip(outgoing, values) if edge == b_value]
  428. raise PrimitiveFinished(a)
  429. def set_remove_node(a, b, **remainder):
  430. outgoing, = yield [("RO", [a])]
  431. elements = yield [("RE", [i]) for i in outgoing]
  432. elements = [elements] if not isinstance(elements[0], list) else elements
  433. yield [("DE", [identifier]) for identifier, edge in zip(outgoing, elements) if edge[1] == b]
  434. raise PrimitiveFinished(a)
  435. def set_in(a, b, **remainder):
  436. # TODO make non-primitive, though compiled
  437. outgoing, b_value = yield [("RO", [a]), ("RV", [b])]
  438. if outgoing:
  439. elements = yield [("RE", [i]) for i in outgoing]
  440. values = yield [("RV", [i[1]]) for i in elements]
  441. if b_value in values:
  442. result, = yield [("CNV", [True])]
  443. else:
  444. result, = yield [("CNV", [False])]
  445. else:
  446. result, = yield [("CNV", [False])]
  447. raise PrimitiveFinished(result)
  448. def set_in_node(a, b, **remainder):
  449. # TODO make non-primitive, though compiled
  450. outgoing, = yield [("RO", [a])]
  451. if outgoing:
  452. elements = yield [("RE", [i]) for i in outgoing]
  453. if b in [v[1] for v in elements]:
  454. result, = yield [("CNV", [True])]
  455. else:
  456. result, = yield [("CNV", [False])]
  457. else:
  458. result, = yield [("CNV", [False])]
  459. raise PrimitiveFinished(result)
  460. def is_edge(a, **remainder):
  461. edge, = yield [("RE", [a])]
  462. result, = yield [("CNV", [edge[0] is not None])]
  463. raise PrimitiveFinished(result)
  464. def log(a, **remainder):
  465. a_value, = yield [("RV", [a])]
  466. print("== LOG == " + str(a_value))
  467. raise PrimitiveFinished(a)
  468. def read_taskroot(task_root, **remainder):
  469. raise PrimitiveFinished(task_root)
  470. def time(**remainder):
  471. a, = yield [("CNV", [python_time.time()])]
  472. raise PrimitiveFinished(a)
  473. def hash(a, **remainder):
  474. a_value, = yield [("RV", [a])]
  475. import hashlib
  476. b_value = hashlib.sha512(a_value).hexdigest()
  477. b, = yield [("CNV", [b_value])]
  478. raise PrimitiveFinished(b)
  479. def __sleep(a, b, **remainder):
  480. timeout, interruptable = yield [("RV", [a]), ("RV", [b])]
  481. yield [("SLEEP", [timeout, interruptable])]
  482. raise PrimitiveFinished(a)