primitives.py 19 KB

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