primitives.py 19 KB

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