tree_ir.py 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. # NOTE: NOP_LITERAL abuses a mechanic of the modelverse kernel. Specifically,
  2. # whenever the `ModelverseKernel.execute_yields` method returns `None`, then
  3. # the server built around it takes that as a hint that an instruction's phase
  4. # has been completed. The server interrupts the kernel's thread of execution
  5. # when it remarks that an instruction has completed a phase (i.e., when `None`
  6. # is returned by `ModelverseKernel.execute_yields`) and proceeds to check for
  7. # input and output.
  8. #
  9. # In assembly language, a nop is usually used as a point at which a thread of
  10. # execution can be terminated. It follows from the paragraph above that what
  11. # the interpreter does is more or less equivalent to placing nops after every
  12. # instruction. It is worthwhile to remark that JIT-compiled code cannot rely
  13. # on the kernel to interrupt the thread of execution automatically during a
  14. # jitted function's execution -- jitted functions are considered equivalent
  15. # to a single instruction as far as the kernel is concerned. A nop will be
  16. # inserted _after_ the function call (if it is called from interpreted code)
  17. # but that does not suffice for IO, which needs the input/output processing
  18. # to be performed during function execution.
  19. #
  20. # For this reason, the JIT must strategically interrupt the execution of the
  21. # functions it compiles. In other words, it must insert its own nops.
  22. # Here comes the interesting part: a nop is equivalent to `yield None`,
  23. # because that will persuade `ModelverseKernel.execute_yields` to relay the
  24. # `None` marker value to the server, without terminating the current
  25. # generator.
  26. NOP_LITERAL = None
  27. """A literal that results in a nop during which execution may be interrupted
  28. when yielded."""
  29. class Instruction(object):
  30. """A base class for instructions. An instruction is essentially a syntax
  31. node that must first be defined, and can only then be used."""
  32. def __init__(self):
  33. self.has_result_cache = None
  34. self.has_definition_cache = None
  35. def has_result(self):
  36. """Tells if this instruction computes a result."""
  37. if self.has_result_cache is None:
  38. self.has_result_cache = self.has_result_impl()
  39. return self.has_result_cache
  40. def has_definition(self):
  41. """Tells if this instruction requires a definition."""
  42. if self.has_definition_cache is None:
  43. self.has_definition_cache = self.has_definition_impl()
  44. return self.has_definition_cache
  45. def has_result_impl(self):
  46. """Tells if this instruction computes a result."""
  47. return True
  48. def has_definition_impl(self):
  49. """Tells if this instruction requires a definition."""
  50. return True
  51. def get_result_name_override(self, code_generator):
  52. """Gets a value that overrides the code generator's result name for this
  53. instruction if it is not None."""
  54. return None
  55. def generate_python_def(self, code_generator):
  56. """Generates a Python statement that executes this instruction.
  57. The statement is appended immediately to the code generator."""
  58. if self.has_definition():
  59. raise NotImplementedError()
  60. else:
  61. code_generator.append_line('pass')
  62. def generate_python_use(self, code_generator):
  63. """Generates a Python expression that retrieves this instruction's
  64. result. The expression is returned as a string."""
  65. if self.has_result():
  66. return code_generator.get_result_name(self)
  67. else:
  68. return 'None'
  69. def get_children(self):
  70. """Gets this instruction's sequence of child instructions."""
  71. raise NotImplementedError()
  72. def create(self, new_children):
  73. """Creates a new instruction of this type from the given sequence of child instructions."""
  74. raise NotImplementedError()
  75. def simplify_node(self):
  76. """Applies basic simplification to this instruction only."""
  77. return self
  78. def simplify(self):
  79. """Applies basic simplification to this instruction and all of its children."""
  80. # This fairly convoluted one-liner first simplifies all children, then creates
  81. # an instruction from the simplified children, and finally simplifies that top-level
  82. # instruction.
  83. return self.create([c.simplify() for c in self.get_children()]).simplify_node()
  84. def __str__(self):
  85. code_generator = PythonGenerator()
  86. self.generate_python_def(code_generator)
  87. return str(code_generator)
  88. class PythonGenerator(object):
  89. """Generates Python code from instructions."""
  90. def __init__(self, combine_state_definitions=True):
  91. self.code = []
  92. self.state_definitions = []
  93. self.state_definition_names = set()
  94. self.indentation_string = ' ' * 4
  95. self.indentation = 0
  96. self.result_name_dict = {}
  97. self.combine_state_definitions = combine_state_definitions
  98. def append(self, text):
  99. """Appends the given string to this code generator."""
  100. self.flush_state_definitions()
  101. self.code.append(text)
  102. def append_indentation(self):
  103. """Appends indentation to the code generator."""
  104. self.append(self.indentation_string * self.indentation)
  105. def append_line(self, line=None):
  106. """Appends the indentation string followed by the given string (if any)
  107. and a newline to the code generator."""
  108. self.append_indentation()
  109. if line is not None:
  110. self.append(line)
  111. self.append('\n')
  112. def increase_indentation(self):
  113. """Increases the code generator's indentation by one indent."""
  114. self.flush_state_definitions()
  115. self.indentation += 1
  116. def decrease_indentation(self):
  117. """Decreases the code generator's indentation by one indent."""
  118. self.flush_state_definitions()
  119. self.indentation -= 1
  120. def get_result_name(self, instruction, advised_name=None):
  121. """Gets the name of the given instruction's result variable."""
  122. if instruction not in self.result_name_dict:
  123. override_name = instruction.get_result_name_override(self)
  124. if override_name is not None:
  125. self.result_name_dict[instruction] = override_name
  126. elif advised_name is not None:
  127. self.result_name_dict[instruction] = advised_name
  128. else:
  129. self.result_name_dict[instruction] = \
  130. 'tmp' + str(len(self.result_name_dict))
  131. result = self.result_name_dict[instruction]
  132. if result in self.state_definition_names:
  133. # This might mean that we're trying to access a name that is
  134. # defined by the current block of state definitions. So we need
  135. # to flush the state definitions now.
  136. self.flush_state_definitions()
  137. return result
  138. def append_definition(self, lhs, rhs):
  139. """Defines the first instruction's result variable as the second
  140. instruction's result."""
  141. self.append_line(
  142. self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
  143. def append_move_definition(self, lhs, rhs):
  144. """First defines the second instruction, then defines the first
  145. instruction as the result of the second."""
  146. if rhs.has_definition():
  147. # Retrieve the result name for the lhs.
  148. lhs_result_name = self.get_result_name(lhs)
  149. # Encourage the rhs to take on the same result name as the lhs.
  150. rhs_result_name = self.get_result_name(rhs, lhs_result_name)
  151. # Generate the rhs' definition.
  152. rhs.generate_python_def(self)
  153. # Only perform an assignment if it's truly necessary.
  154. if lhs_result_name != rhs_result_name:
  155. self.append_definition(lhs, rhs)
  156. else:
  157. self.append_definition(lhs, rhs)
  158. def append_state_definition(self, lhs, opcode, args):
  159. """Appends a definition that queries the modelverse state."""
  160. result_name = self.get_result_name(lhs)
  161. request_tuple = '(%s, [%s])' % (
  162. repr(opcode),
  163. ', '.join([arg_i.generate_python_use(self) for arg_i in args]))
  164. self.state_definitions.append((result_name, request_tuple))
  165. self.state_definition_names.add(result_name)
  166. if not self.combine_state_definitions:
  167. self.flush_state_definitions()
  168. def flush_state_definitions(self):
  169. """Flushes the list of state-access definitions to the generated code."""
  170. state_defs = self.state_definitions
  171. if len(state_defs) > 0:
  172. # Clear state_definitions _before_ calling append_line, because append_line
  173. # will call flush_state_definitions. Clearing state_definitions afterward
  174. # will result in infinite recursion.
  175. self.state_definitions = []
  176. self.state_definition_names = set()
  177. if len(state_defs) == 1:
  178. self.append_line('%s, = yield [%s]' % state_defs[0])
  179. else:
  180. self.append_line(
  181. "%s = yield [%s]" % (
  182. ', '.join([name for name, _ in state_defs]),
  183. ', '.join([def_val for _, def_val in state_defs])))
  184. def __str__(self):
  185. self.flush_state_definitions()
  186. return ''.join(self.code)
  187. class VoidInstruction(Instruction):
  188. """A base class for instructions that do not return a value."""
  189. def has_result_impl(self):
  190. """Tells if this instruction computes a result."""
  191. return False
  192. def get_children(self):
  193. """Gets this instruction's sequence of child instructions."""
  194. return []
  195. def create(self, new_children):
  196. """Creates a new instruction of this type from the given sequence of child instructions."""
  197. return self
  198. class EmptyInstruction(VoidInstruction):
  199. """Represents the empty instruction, which does nothing."""
  200. def has_definition_impl(self):
  201. """Tells if this instruction requires a definition."""
  202. return False
  203. class SelectInstruction(Instruction):
  204. """Represents a select-instruction: an instruction that defines one of two
  205. child instructions, and sets its result to the defined child's result."""
  206. def __init__(self, condition, if_clause, else_clause):
  207. Instruction.__init__(self)
  208. self.condition = condition
  209. self.if_clause = if_clause
  210. self.else_clause = else_clause
  211. def has_result_impl(self):
  212. """Tells if this instruction computes a result."""
  213. return self.if_clause.has_result() or self.else_clause.has_result()
  214. def simplify_node(self):
  215. """Applies basic simplification to this instruction only."""
  216. if isinstance(self.condition, LiteralInstruction):
  217. return self.if_clause if self.condition.literal else self.else_clause
  218. else:
  219. return SelectInstruction(self.condition, self.if_clause, self.else_clause)
  220. def get_children(self):
  221. """Gets this instruction's sequence of child instructions."""
  222. return [self.condition, self.if_clause, self.else_clause]
  223. def create(self, new_children):
  224. """Creates a new instruction of this type from the given sequence of child instructions."""
  225. condition, if_clause, else_clause = new_children
  226. return SelectInstruction(condition, if_clause, else_clause)
  227. def generate_python_def(self, code_generator):
  228. """Generates Python code for this instruction."""
  229. if_has_result = self.has_result()
  230. if self.condition.has_definition():
  231. self.condition.generate_python_def(code_generator)
  232. code_generator.append_line(
  233. 'if ' + self.condition.generate_python_use(code_generator) + ':')
  234. code_generator.increase_indentation()
  235. if if_has_result:
  236. code_generator.append_move_definition(self, self.if_clause)
  237. else:
  238. self.if_clause.generate_python_def(code_generator)
  239. code_generator.decrease_indentation()
  240. else_has_def = self.else_clause.has_definition()
  241. if else_has_def or if_has_result:
  242. code_generator.append_line('else:')
  243. code_generator.increase_indentation()
  244. if if_has_result:
  245. code_generator.append_move_definition(self, self.else_clause)
  246. else:
  247. self.else_clause.generate_python_def(code_generator)
  248. code_generator.decrease_indentation()
  249. class ReturnInstruction(VoidInstruction):
  250. """Represents a return-instruction."""
  251. def __init__(self, value):
  252. VoidInstruction.__init__(self)
  253. self.value = value
  254. def get_children(self):
  255. """Gets this instruction's sequence of child instructions."""
  256. return [self.value]
  257. def create(self, new_children):
  258. """Creates a new instruction of this type from the given sequence of child instructions."""
  259. value, = new_children
  260. return ReturnInstruction(value)
  261. def generate_python_def(self, code_generator):
  262. """Generates Python code for this instruction."""
  263. if self.value.has_definition():
  264. self.value.generate_python_def(code_generator)
  265. code_generator.append_line(
  266. 'raise PrimitiveFinished(' +
  267. self.value.generate_python_use(code_generator) +
  268. ')')
  269. class RaiseInstruction(VoidInstruction):
  270. """An instruction that raises an error."""
  271. def __init__(self, value):
  272. VoidInstruction.__init__(self)
  273. self.value = value
  274. def get_children(self):
  275. """Gets this instruction's sequence of child instructions."""
  276. return [self.value]
  277. def create(self, new_children):
  278. """Creates a new instruction of this type from the given sequence of child instructions."""
  279. value, = new_children
  280. return RaiseInstruction(value)
  281. def generate_python_def(self, code_generator):
  282. """Generates Python code for this instruction."""
  283. self.value.generate_python_def(code_generator)
  284. code_generator.append_line(
  285. 'raise ' + self.value.generate_python_use(code_generator))
  286. class CallInstruction(Instruction):
  287. """An instruction that performs a simple call."""
  288. def __init__(self, target, argument_list):
  289. Instruction.__init__(self)
  290. self.target = target
  291. self.argument_list = argument_list
  292. def get_children(self):
  293. """Gets this instruction's sequence of child instructions."""
  294. return [self.target] + self.argument_list
  295. def create(self, new_children):
  296. """Creates a new instruction of this type from the given sequence of child instructions."""
  297. return CallInstruction(new_children[0], new_children[1:])
  298. def generate_python_def(self, code_generator):
  299. """Generates Python code for this instruction."""
  300. if self.target.has_definition():
  301. self.target.generate_python_def(code_generator)
  302. for arg in self.argument_list:
  303. if arg.has_definition():
  304. arg.generate_python_def(code_generator)
  305. code_generator.append_line(
  306. '%s = %s(%s)' % (
  307. code_generator.get_result_name(self),
  308. self.target.generate_python_use(code_generator),
  309. ', '.join([arg.generate_python_use(code_generator) for arg in self.argument_list])))
  310. class JitCallInstruction(Instruction):
  311. """An instruction that calls a jitted function."""
  312. def __init__(self, target, named_args, kwarg):
  313. Instruction.__init__(self)
  314. self.target = target
  315. self.named_args = named_args
  316. self.kwarg = kwarg
  317. def get_children(self):
  318. """Gets this instruction's sequence of child instructions."""
  319. return [self.target] + [arg for _, arg in self.named_args] + [self.kwarg]
  320. def create(self, new_children):
  321. """Creates a new instruction of this type from the given sequence of child instructions."""
  322. param_names = [name for name, _ in self.named_args]
  323. return JitCallInstruction(
  324. new_children[0], zip(param_names, new_children[1:-1]), new_children[-1])
  325. def generate_python_def(self, code_generator):
  326. """Generates Python code for this instruction."""
  327. if self.target.has_definition():
  328. self.target.generate_python_def(code_generator)
  329. arg_list = []
  330. for param_name, arg in self.named_args:
  331. if arg.has_definition():
  332. arg.generate_python_def(code_generator)
  333. arg_list.append(
  334. '%s=%s' % (param_name, arg.generate_python_use(code_generator)))
  335. if self.kwarg.has_definition():
  336. self.kwarg.generate_python_def(code_generator)
  337. arg_list.append(
  338. '**%s' % self.kwarg.generate_python_use(code_generator))
  339. own_name = code_generator.get_result_name(self)
  340. code_generator.append_line('try:')
  341. code_generator.increase_indentation()
  342. code_generator.append_line(
  343. '%s_gen = %s(%s)' % (
  344. own_name,
  345. self.target.generate_python_use(code_generator),
  346. ', '.join(arg_list)))
  347. code_generator.append_line('%s_inp = None' % own_name)
  348. code_generator.append_line('while 1:')
  349. code_generator.increase_indentation()
  350. code_generator.append_line(
  351. '%s_inp = yield %s_gen.send(%s_inp)' % (own_name, own_name, own_name))
  352. code_generator.decrease_indentation()
  353. code_generator.decrease_indentation()
  354. code_generator.append_line('except PrimitiveFinished as %s_ex:' % own_name)
  355. code_generator.increase_indentation()
  356. code_generator.append_line('%s = %s_ex.result' % (own_name, own_name))
  357. code_generator.decrease_indentation()
  358. class PrintInstruction(Instruction):
  359. """An instruction that prints a value."""
  360. def __init__(self, argument):
  361. Instruction.__init__(self)
  362. self.argument = argument
  363. def has_result_impl(self):
  364. """Tells if this instruction has a result."""
  365. return False
  366. def get_children(self):
  367. """Gets this instruction's sequence of child instructions."""
  368. return [self.argument]
  369. def create(self, new_children):
  370. """Creates a new instruction of this type from the given sequence of child instructions."""
  371. arg, = new_children
  372. return PrintInstruction(arg)
  373. def generate_python_def(self, code_generator):
  374. """Generates Python code for this instruction."""
  375. if self.argument.has_definition():
  376. self.argument.generate_python_def(code_generator)
  377. code_generator.append_line(
  378. 'print(%s)' % (
  379. self.argument.generate_python_use(code_generator)))
  380. class BinaryInstruction(Instruction):
  381. """An instruction that performs a binary operation."""
  382. def __init__(self, lhs, operator, rhs):
  383. Instruction.__init__(self)
  384. self.lhs = lhs
  385. self.operator = operator
  386. self.rhs = rhs
  387. def has_definition_impl(self):
  388. """Tells if this instruction requires a definition."""
  389. return self.lhs.has_definition() or self.rhs.has_definition()
  390. def get_children(self):
  391. """Gets this instruction's sequence of child instructions."""
  392. return [self.lhs, self.rhs]
  393. def create(self, new_children):
  394. """Creates a new instruction of this type from the given sequence of child instructions."""
  395. lhs, rhs, = new_children
  396. return BinaryInstruction(lhs, self.operator, rhs)
  397. def simplify_node(self):
  398. """Applies basic simplification to this instruction only."""
  399. if isinstance(self.lhs, LiteralInstruction) and isinstance(self.rhs, LiteralInstruction):
  400. # TODO: there's probably a better way to do this than with eval.
  401. return LiteralInstruction(
  402. eval('%s %s %s' % (repr(self.lhs.literal), self.operator, repr(self.rhs.literal))))
  403. else:
  404. return self
  405. def generate_python_use(self, code_generator):
  406. """Generates a Python expression that retrieves this instruction's
  407. result. The expression is returned as a string."""
  408. return '(%s %s %s)' % (
  409. self.lhs.generate_python_use(code_generator),
  410. self.operator,
  411. self.rhs.generate_python_use(code_generator))
  412. def generate_python_def(self, code_generator):
  413. """Generates a Python statement that executes this instruction.
  414. The statement is appended immediately to the code generator."""
  415. if self.lhs.has_definition():
  416. self.lhs.generate_python_def(code_generator)
  417. if self.rhs.has_definition():
  418. self.rhs.generate_python_def(code_generator)
  419. elif self.rhs.has_definition():
  420. self.rhs.generate_python_def(code_generator)
  421. else:
  422. code_generator.append_line('pass')
  423. class UnaryInstruction(Instruction):
  424. """An instruction that performs a unary operation."""
  425. def __init__(self, operator, operand):
  426. Instruction.__init__(self)
  427. self.operator = operator
  428. self.operand = operand
  429. def has_definition_impl(self):
  430. """Tells if this instruction requires a definition."""
  431. return self.operand.has_definition()
  432. def get_children(self):
  433. """Gets this instruction's sequence of child instructions."""
  434. return [self.operand]
  435. def create(self, new_children):
  436. """Creates a new instruction of this type from the given sequence of child instructions."""
  437. operand, = new_children
  438. return UnaryInstruction(self.operator, operand)
  439. def simplify_node(self):
  440. """Applies basic simplification to this instruction only."""
  441. if isinstance(self.operand, LiteralInstruction):
  442. # TODO: there's probably a better way to do this than with eval.
  443. return LiteralInstruction(
  444. eval('%s %s' % (self.operator, repr(self.operand.literal))))
  445. else:
  446. return self
  447. def generate_python_use(self, code_generator):
  448. """Generates a Python expression that retrieves this instruction's
  449. result. The expression is returned as a string."""
  450. return '(%s %s)' % (
  451. self.operator,
  452. self.operand.generate_python_use(code_generator))
  453. def generate_python_def(self, code_generator):
  454. """Generates a Python statement that executes this instruction.
  455. The statement is appended immediately to the code generator."""
  456. if self.operand.has_definition():
  457. self.operand.generate_python_def(code_generator)
  458. else:
  459. code_generator.append_line('pass')
  460. class LoopInstruction(VoidInstruction):
  461. """Represents a loop-instruction, which loops until broken."""
  462. def __init__(self, body):
  463. VoidInstruction.__init__(self)
  464. self.body = body
  465. def get_children(self):
  466. """Gets this instruction's sequence of child instructions."""
  467. return [self.body]
  468. def create(self, new_children):
  469. """Creates a new instruction of this type from the given sequence of child instructions."""
  470. body, = new_children
  471. return LoopInstruction(body)
  472. def generate_python_def(self, code_generator):
  473. """Generates Python code for this instruction."""
  474. code_generator.append_line('while 1:')
  475. code_generator.increase_indentation()
  476. self.body.generate_python_def(code_generator)
  477. code_generator.decrease_indentation()
  478. class BreakInstruction(VoidInstruction):
  479. """Represents a break-instruction."""
  480. def generate_python_def(self, code_generator):
  481. """Generates Python code for this instruction."""
  482. code_generator.append_line('break')
  483. class ContinueInstruction(VoidInstruction):
  484. """Represents a continue-instruction."""
  485. def generate_python_def(self, code_generator):
  486. """Generates Python code for this instruction."""
  487. code_generator.append_line('continue')
  488. class CompoundInstruction(Instruction):
  489. """Represents an instruction that evaluates two other instructions
  490. in order, and returns the second instruction's result."""
  491. def __init__(self, first, second):
  492. Instruction.__init__(self)
  493. self.first = first
  494. self.second = second
  495. def has_result_impl(self):
  496. """Tells if this instruction has a result."""
  497. return self.second.has_result() or self.first.has_result()
  498. def get_children(self):
  499. """Gets this instruction's sequence of child instructions."""
  500. return [self.first, self.second]
  501. def create(self, new_children):
  502. """Creates a new instruction of this type from the given sequence of child instructions."""
  503. first, second = new_children
  504. return CompoundInstruction(first, second)
  505. def simplify_node(self):
  506. """Applies basic simplification to this instruction and its children."""
  507. if not self.first.has_definition() and (
  508. not self.first.has_result() or self.second.has_result()):
  509. return self.second
  510. elif (not self.second.has_definition()) and (not self.second.has_result()):
  511. return self.first
  512. else:
  513. return self
  514. def generate_python_def(self, code_generator):
  515. """Generates Python code for this instruction."""
  516. if self.second.has_result():
  517. self.first.generate_python_def(code_generator)
  518. code_generator.append_move_definition(self, self.second)
  519. elif self.first.has_result():
  520. code_generator.append_move_definition(self, self.first)
  521. self.second.generate_python_def(code_generator)
  522. else:
  523. self.first.generate_python_def(code_generator)
  524. self.second.generate_python_def(code_generator)
  525. class LiteralInstruction(Instruction):
  526. """Represents an integer, floating-point, string or Boolean literal."""
  527. def __init__(self, literal):
  528. Instruction.__init__(self)
  529. self.literal = literal
  530. def has_definition_impl(self):
  531. """Tells if this instruction requires a definition."""
  532. return False
  533. def get_children(self):
  534. """Gets this instruction's sequence of child instructions."""
  535. return []
  536. def create(self, new_children):
  537. """Creates a new instruction of this type from the given sequence of child instructions."""
  538. return self
  539. def generate_python_use(self, code_generator):
  540. """Generates a Python expression that retrieves this instruction's
  541. result. The expression is returned as a string."""
  542. return repr(self.literal)
  543. class DictionaryLiteralInstruction(Instruction):
  544. """Constructs a dictionary literal."""
  545. def __init__(self, key_value_pairs):
  546. Instruction.__init__(self)
  547. self.key_value_pairs = key_value_pairs
  548. def get_children(self):
  549. """Gets this instruction's sequence of child instructions."""
  550. return [val for _, val in self.key_value_pairs]
  551. def create(self, new_children):
  552. """Creates a new instruction of this type from the given sequence of child instructions."""
  553. keys = [k for k, _ in self.key_value_pairs]
  554. return DictionaryLiteralInstruction(zip(keys, new_children))
  555. def has_definition(self):
  556. """Tells if this instruction requires a definition."""
  557. return any(
  558. [key.has_definition() or val.has_definition()
  559. for key, val in self.key_value_pairs])
  560. def simplify(self):
  561. """Applies basic simplification to this instruction and its children."""
  562. return DictionaryLiteralInstruction(
  563. [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
  564. def generate_python_def(self, code_generator):
  565. """Generates a Python statement that executes this instruction.
  566. The statement is appended immediately to the code generator."""
  567. for key, val in self.key_value_pairs:
  568. if key.has_definition():
  569. key.generate_python_def(code_generator)
  570. if val.has_definition():
  571. val.generate_python_def(code_generator)
  572. def generate_python_use(self, code_generator):
  573. """Generates a Python expression that retrieves this instruction's
  574. result. The expression is returned as a string."""
  575. return '{ %s }' % ', '.join(
  576. ['%s : %s' % (
  577. key.generate_python_use(code_generator),
  578. val.generate_python_use(code_generator))
  579. for key, val in self.key_value_pairs])
  580. class StateInstruction(Instruction):
  581. """An instruction that accesses the modelverse state."""
  582. def get_opcode(self):
  583. """Gets the opcode for this state instruction."""
  584. raise NotImplementedError()
  585. def get_arguments(self):
  586. """Gets this state instruction's argument list."""
  587. raise NotImplementedError()
  588. def get_children(self):
  589. """Gets this instruction's sequence of child instructions."""
  590. return self.get_arguments()
  591. def create(self, new_children):
  592. """Creates a new instruction of this type from the given sequence of child instructions."""
  593. return type(self)(*new_children)
  594. def generate_python_def(self, code_generator):
  595. """Generates a Python statement that executes this instruction.
  596. The statement is appended immediately to the code generator."""
  597. args = self.get_arguments()
  598. for arg_i in args:
  599. if arg_i.has_definition():
  600. arg_i.generate_python_def(code_generator)
  601. code_generator.append_state_definition(self, self.get_opcode(), args)
  602. class VariableName(object):
  603. """A data structure that unifies names across instructions that access the
  604. same variable."""
  605. def __init__(self, name):
  606. self.name = name
  607. def get_result_name_override(self, _):
  608. """Gets a value that overrides the code generator's result name for this
  609. instruction if it is not None."""
  610. return self.name
  611. class VariableInstruction(Instruction):
  612. """A base class for instructions that access variables."""
  613. def __init__(self, name):
  614. Instruction.__init__(self)
  615. if isinstance(name, str) or isinstance(name, unicode) or name is None:
  616. self.name = VariableName(name)
  617. else:
  618. self.name = name
  619. def get_children(self):
  620. """Gets this instruction's sequence of child instructions."""
  621. raise NotImplementedError()
  622. def create(self, new_children):
  623. """Creates a new instruction of this type from the given sequence of child instructions."""
  624. raise NotImplementedError()
  625. def get_result_name_override(self, code_generator):
  626. """Gets a value that overrides the code generator's result name for this
  627. instruction if it is not None."""
  628. return code_generator.get_result_name(self.name)
  629. class LocalInstruction(VariableInstruction):
  630. """A base class for instructions that access local variables."""
  631. def get_children(self):
  632. """Gets this instruction's sequence of child instructions."""
  633. raise NotImplementedError()
  634. def create(self, new_children):
  635. """Creates a new instruction of this type from the given sequence of child instructions."""
  636. raise NotImplementedError()
  637. def create_load(self):
  638. """Creates an instruction that loads the variable referenced by this instruction."""
  639. return LoadLocalInstruction(self.name)
  640. def create_store(self, value):
  641. """Creates an instruction that stores the given value in the variable referenced
  642. by this instruction."""
  643. return StoreLocalInstruction(self.name, value)
  644. class StoreLocalInstruction(LocalInstruction):
  645. """An instruction that stores a value in a local variable."""
  646. def __init__(self, name, value):
  647. LocalInstruction.__init__(self, name)
  648. self.value = value
  649. def get_children(self):
  650. """Gets this instruction's sequence of child instructions."""
  651. return [self.value]
  652. def create(self, new_children):
  653. """Creates a new instruction of this type from the given sequence of child instructions."""
  654. val, = new_children
  655. return StoreLocalInstruction(self.name, val)
  656. def generate_python_def(self, code_generator):
  657. """Generates a Python statement that executes this instruction.
  658. The statement is appended immediately to the code generator."""
  659. code_generator.append_move_definition(self, self.value)
  660. class LoadLocalInstruction(LocalInstruction):
  661. """An instruction that loads a value from a local variable."""
  662. def has_definition_impl(self):
  663. """Tells if this instruction requires a definition."""
  664. return False
  665. def get_children(self):
  666. """Gets this instruction's sequence of child instructions."""
  667. return []
  668. def create(self, new_children):
  669. """Creates a new instruction of this type from the given sequence of child instructions."""
  670. return self
  671. class DefineFunctionInstruction(VariableInstruction):
  672. """An instruction that defines a function."""
  673. def __init__(self, name, parameter_list, body):
  674. VariableInstruction.__init__(self, name)
  675. self.parameter_list = parameter_list
  676. self.body = body
  677. def get_children(self):
  678. """Gets this instruction's sequence of child instructions."""
  679. return [self.body]
  680. def create(self, new_children):
  681. """Creates a new instruction of this type from the given sequence of child instructions."""
  682. body, = new_children
  683. return DefineFunctionInstruction(self.name, self.parameter_list, body)
  684. def generate_python_def(self, code_generator):
  685. """Generates a Python statement that executes this instruction.
  686. The statement is appended immediately to the code generator."""
  687. code_generator.append_line('def %s(%s):' % (
  688. code_generator.get_result_name(self), ', '.join(self.parameter_list)))
  689. code_generator.increase_indentation()
  690. self.body.generate_python_def(code_generator)
  691. code_generator.decrease_indentation()
  692. class LocalExistsInstruction(LocalInstruction):
  693. """An instruction that checks if a local variable exists."""
  694. def has_definition_impl(self):
  695. """Tells if this instruction requires a definition."""
  696. return False
  697. def get_children(self):
  698. """Gets this instruction's sequence of child instructions."""
  699. return []
  700. def create(self, new_children):
  701. """Creates a new instruction of this type from the given sequence of child instructions."""
  702. return self
  703. def generate_python_use(self, code_generator):
  704. """Generates a Python expression that retrieves this instruction's
  705. result. The expression is returned as a string."""
  706. return "'%s' in locals()" % self.get_result_name_override(code_generator)
  707. class LoadGlobalInstruction(VariableInstruction):
  708. """An instruction that loads a value from a global variable."""
  709. def has_definition_impl(self):
  710. """Tells if this instruction requires a definition."""
  711. return False
  712. def get_children(self):
  713. """Gets this instruction's sequence of child instructions."""
  714. return []
  715. def create(self, new_children):
  716. """Creates a new instruction of this type from the given sequence of child instructions."""
  717. return self
  718. class LoadIndexInstruction(Instruction):
  719. """An instruction that produces a value by indexing a specified expression with
  720. a given key."""
  721. def __init__(self, indexed, key):
  722. Instruction.__init__(self)
  723. self.indexed = indexed
  724. self.key = key
  725. def has_definition_impl(self):
  726. """Tells if this instruction requires a definition."""
  727. return False
  728. def get_children(self):
  729. """Gets this instruction's sequence of child instructions."""
  730. return [self.indexed, self.key]
  731. def create(self, new_children):
  732. """Creates a new instruction of this type from the given sequence of child instructions."""
  733. indexed, key = new_children
  734. return LoadIndexInstruction(indexed, key)
  735. def generate_python_use(self, code_generator):
  736. """Generates a Python expression that retrieves this instruction's
  737. result. The expression is returned as a string."""
  738. if self.indexed.has_definition():
  739. self.indexed.generate_python_def(code_generator)
  740. if self.key.has_definition():
  741. self.key.generate_python_def(code_generator)
  742. return "%s[%s]" % (
  743. self.indexed.generate_python_use(code_generator),
  744. self.key.generate_python_use(code_generator))
  745. class LoadMemberInstruction(Instruction):
  746. """An instruction that produces a value by loading a member from a container."""
  747. def __init__(self, container, member_name):
  748. Instruction.__init__(self)
  749. self.container = container
  750. self.member_name = member_name
  751. def has_definition_impl(self):
  752. """Tells if this instruction requires a definition."""
  753. return self.container.has_definition()
  754. def get_children(self):
  755. """Gets this instruction's sequence of child instructions."""
  756. return [self.container]
  757. def create(self, new_children):
  758. """Creates a new instruction of this type from the given sequence of child instructions."""
  759. container, = new_children
  760. return LoadMemberInstruction(container, self.member_name)
  761. def generate_python_def(self, code_generator):
  762. """Generates a Python statement that executes this instruction.
  763. The statement is appended immediately to the code generator."""
  764. self.container.generate_python_def(code_generator)
  765. def generate_python_use(self, code_generator):
  766. """Generates a Python expression that retrieves this instruction's
  767. result. The expression is returned as a string."""
  768. return "%s.%s" % (
  769. self.container.generate_python_use(code_generator),
  770. self.member_name)
  771. class StoreMemberInstruction(Instruction):
  772. """An instruction that stores a value in a container member."""
  773. def __init__(self, container, member_name, value):
  774. Instruction.__init__(self)
  775. self.container = container
  776. self.member_name = member_name
  777. self.value = value
  778. def has_definition_impl(self):
  779. """Tells if this instruction requires a definition."""
  780. return True
  781. def has_result_impl(self):
  782. """Tells if this instruction computes a result."""
  783. return False
  784. def get_children(self):
  785. """Gets this instruction's sequence of child instructions."""
  786. return [self.container, self.value]
  787. def create(self, new_children):
  788. """Creates a new instruction of this type from the given sequence of child instructions."""
  789. container, value = new_children
  790. return StoreMemberInstruction(container, self.member_name, value)
  791. def generate_python_def(self, code_generator):
  792. """Generates a Python statement that executes this instruction.
  793. The statement is appended immediately to the code generator."""
  794. if self.container.has_definition():
  795. self.container.generate_python_def(code_generator)
  796. code_generator.append_line('%s.%s = %s' % (
  797. self.container.generate_python_use(code_generator),
  798. self.member_name,
  799. self.value.generate_python_use(code_generator)))
  800. class NopInstruction(Instruction):
  801. """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
  802. def has_result_impl(self):
  803. """Tells if this instruction computes a result."""
  804. return False
  805. def get_children(self):
  806. """Gets this instruction's sequence of child instructions."""
  807. return []
  808. def create(self, new_children):
  809. """Creates a new instruction of this type from the given sequence of child instructions."""
  810. return self
  811. def generate_python_def(self, code_generator):
  812. """Generates a Python statement that executes this instruction.
  813. The statement is appended immediately to the code generator."""
  814. code_generator.append_line('yield %s' % repr(NOP_LITERAL))
  815. class ReadValueInstruction(StateInstruction):
  816. """An instruction that reads a value from a node."""
  817. def __init__(self, node_id):
  818. StateInstruction.__init__(self)
  819. self.node_id = node_id
  820. def simplify_node(self):
  821. """Applies basic simplification to this instruction only."""
  822. if isinstance(self.node_id, CreateNodeWithValueInstruction):
  823. return self.node_id.value
  824. else:
  825. return self
  826. def get_opcode(self):
  827. """Gets the opcode for this state instruction."""
  828. return "RV"
  829. def get_arguments(self):
  830. """Gets this state instruction's argument list."""
  831. return [self.node_id]
  832. class ReadDictionaryValueInstruction(StateInstruction):
  833. """An instruction that reads a dictionary value."""
  834. def __init__(self, node_id, key):
  835. StateInstruction.__init__(self)
  836. self.node_id = node_id
  837. self.key = key
  838. def get_opcode(self):
  839. """Gets the opcode for this state instruction."""
  840. return "RD"
  841. def get_arguments(self):
  842. """Gets this state instruction's argument list."""
  843. return [self.node_id, self.key]
  844. class ReadDictionaryEdgeInstruction(StateInstruction):
  845. """An instruction that reads a dictionary edge."""
  846. def __init__(self, node_id, key):
  847. StateInstruction.__init__(self)
  848. self.node_id = node_id
  849. self.key = key
  850. def get_opcode(self):
  851. """Gets the opcode for this state instruction."""
  852. return "RDE"
  853. def get_arguments(self):
  854. """Gets this state instruction's argument list."""
  855. return [self.node_id, self.key]
  856. class ReadEdgeInstruction(StateInstruction):
  857. """An instruction that reads an edge."""
  858. def __init__(self, node_id):
  859. StateInstruction.__init__(self)
  860. self.node_id = node_id
  861. def get_opcode(self):
  862. """Gets the opcode for this state instruction."""
  863. return "RE"
  864. def get_arguments(self):
  865. """Gets this state instruction's argument list."""
  866. return [self.node_id]
  867. class ReadOutgoingEdgesInstruction(StateInstruction):
  868. """An instruction that reads all outgoing edges for a node."""
  869. def __init__(self, node_id):
  870. StateInstruction.__init__(self)
  871. self.node_id = node_id
  872. def get_opcode(self):
  873. """Gets the opcode for this state instruction."""
  874. return "RO"
  875. def get_arguments(self):
  876. """Gets this state instruction's argument list."""
  877. return [self.node_id]
  878. class ReadIncomingEdgesInstruction(StateInstruction):
  879. """An instruction that reads all incoming edges for a node."""
  880. def __init__(self, node_id):
  881. StateInstruction.__init__(self)
  882. self.node_id = node_id
  883. def get_opcode(self):
  884. """Gets the opcode for this state instruction."""
  885. return "RI"
  886. def get_arguments(self):
  887. """Gets this state instruction's argument list."""
  888. return [self.node_id]
  889. class CreateNodeInstruction(StateInstruction):
  890. """An instruction that creates an empty node."""
  891. def get_opcode(self):
  892. """Gets the opcode for this state instruction."""
  893. return "CN"
  894. def get_arguments(self):
  895. """Gets this state instruction's argument list."""
  896. return []
  897. class CreateNodeWithValueInstruction(StateInstruction):
  898. """An instruction that creates a node with a given value."""
  899. def __init__(self, value):
  900. StateInstruction.__init__(self)
  901. self.value = value
  902. def get_opcode(self):
  903. """Gets the opcode for this state instruction."""
  904. return "CNV"
  905. def get_arguments(self):
  906. """Gets this state instruction's argument list."""
  907. return [self.value]
  908. class CreateEdgeInstruction(StateInstruction):
  909. """An instruction that creates an edge."""
  910. def __init__(self, source_id, target_id):
  911. StateInstruction.__init__(self)
  912. self.source_id = source_id
  913. self.target_id = target_id
  914. def get_opcode(self):
  915. """Gets the opcode for this state instruction."""
  916. return "CE"
  917. def get_arguments(self):
  918. """Gets this state instruction's argument list."""
  919. return [self.source_id, self.target_id]
  920. class CreateDictionaryEdgeInstruction(StateInstruction):
  921. """An instruction that creates a dictionary edge."""
  922. def __init__(self, source_id, key, target_id):
  923. StateInstruction.__init__(self)
  924. self.source_id = source_id
  925. self.key = key
  926. self.target_id = target_id
  927. def get_opcode(self):
  928. """Gets the opcode for this state instruction."""
  929. return "CD"
  930. def get_arguments(self):
  931. """Gets this state instruction's argument list."""
  932. return [self.source_id, self.key, self.target_id]
  933. class DeleteNodeInstruction(StateInstruction):
  934. """An instruction that deletes a node."""
  935. def __init__(self, node_id):
  936. StateInstruction.__init__(self)
  937. self.node_id = node_id
  938. def has_result(self):
  939. """Tells if this instruction computes a result."""
  940. return False
  941. def get_opcode(self):
  942. """Gets the opcode for this state instruction."""
  943. return "DN"
  944. def get_arguments(self):
  945. """Gets this state instruction's argument list."""
  946. return [self.node_id]
  947. class DeleteEdgeInstruction(StateInstruction):
  948. """An instruction that deletes an edge."""
  949. def __init__(self, edge_id):
  950. StateInstruction.__init__(self)
  951. self.edge_id = edge_id
  952. def has_result(self):
  953. """Tells if this instruction computes a result."""
  954. return False
  955. def get_opcode(self):
  956. """Gets the opcode for this state instruction."""
  957. return "DE"
  958. def get_arguments(self):
  959. """Gets this state instruction's argument list."""
  960. return [self.edge_id]
  961. def create_block(*statements):
  962. """Creates a block-statement from the given list of statements."""
  963. length = len(statements)
  964. if length == 0:
  965. return EmptyInstruction()
  966. elif length == 1:
  967. return statements[0]
  968. else:
  969. return CompoundInstruction(
  970. statements[0],
  971. create_block(*statements[1:]))
  972. def with_debug_info_trace(instruction, debug_info, function_name):
  973. """Prepends the given instruction with a tracing instruction that prints
  974. the given debug information and function name."""
  975. if debug_info is None and function_name is None:
  976. return instruction
  977. else:
  978. if debug_info is None:
  979. debug_info = 'unknown location'
  980. if function_name is None:
  981. function_name = 'unknown function'
  982. return create_block(
  983. PrintInstruction(
  984. LiteralInstruction('TRACE: %s(%s, JIT)' % (debug_info, function_name))),
  985. instruction)
  986. def map_and_simplify(function, instruction):
  987. """Applies the given mapping function to every instruction in the tree
  988. that has the given instruction as root, and simplifies it on-the-fly.
  989. This is at least as powerful as first mapping and then simplifying, as
  990. maps and simplifications are interspersed."""
  991. # Let's just agree to disagree on map vs list comprehensions, pylint.
  992. # pylint: disable=I0011,W0141
  993. return function(
  994. instruction.create(
  995. map(map_and_simplify, instruction.get_children()))).simplify_node()
  996. if __name__ == "__main__":
  997. example_tree = SelectInstruction(
  998. LiteralInstruction(True),
  999. LoopInstruction(
  1000. CompoundInstruction(
  1001. BreakInstruction(),
  1002. CompoundInstruction(
  1003. EmptyInstruction(),
  1004. ContinueInstruction()
  1005. )
  1006. )
  1007. ),
  1008. ReturnInstruction(
  1009. EmptyInstruction()))
  1010. print(example_tree.simplify())