tree_ir.py 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  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 simplify_node(self):
  262. """Applies basic simplification to this instruction only."""
  263. # If we have a return whose value is a call, then we can rewrite
  264. # that as a tail call and save us a stack frame.
  265. def rewrite_call(instruction):
  266. """Rewrites the given instruction in tail-call form, or returns
  267. None."""
  268. if isinstance(instruction, RunGeneratorFunctionInstruction):
  269. return RunTailGeneratorFunctionInstruction(*instruction.get_children())
  270. elif isinstance(instruction, CompoundInstruction):
  271. snd_rewritten = rewrite_call(instruction.second)
  272. if snd_rewritten is not None:
  273. return CompoundInstruction(instruction.first, snd_rewritten)
  274. return None
  275. rewritten_value = rewrite_call(self.value)
  276. if rewritten_value is None:
  277. return self
  278. else:
  279. # We don't even need to create a return here, because tail calls terminate
  280. # the current stack frame anyway.
  281. return rewritten_value
  282. def generate_python_def(self, code_generator):
  283. """Generates Python code for this instruction."""
  284. if self.value.has_definition():
  285. self.value.generate_python_def(code_generator)
  286. code_generator.append_line(
  287. 'raise PrimitiveFinished(' +
  288. self.value.generate_python_use(code_generator) +
  289. ')')
  290. class RaiseInstruction(VoidInstruction):
  291. """An instruction that raises an error."""
  292. def __init__(self, value):
  293. VoidInstruction.__init__(self)
  294. self.value = value
  295. def get_children(self):
  296. """Gets this instruction's sequence of child instructions."""
  297. return [self.value]
  298. def create(self, new_children):
  299. """Creates a new instruction of this type from the given sequence of child instructions."""
  300. value, = new_children
  301. return RaiseInstruction(value)
  302. def generate_python_def(self, code_generator):
  303. """Generates Python code for this instruction."""
  304. self.value.generate_python_def(code_generator)
  305. code_generator.append_line(
  306. 'raise ' + self.value.generate_python_use(code_generator))
  307. class CallInstruction(Instruction):
  308. """An instruction that performs a simple call."""
  309. def __init__(self, target, argument_list):
  310. Instruction.__init__(self)
  311. self.target = target
  312. self.argument_list = argument_list
  313. def get_children(self):
  314. """Gets this instruction's sequence of child instructions."""
  315. return [self.target] + self.argument_list
  316. def create(self, new_children):
  317. """Creates a new instruction of this type from the given sequence of child instructions."""
  318. return CallInstruction(new_children[0], new_children[1:])
  319. def generate_python_def(self, code_generator):
  320. """Generates Python code for this instruction."""
  321. if self.target.has_definition():
  322. self.target.generate_python_def(code_generator)
  323. for arg in self.argument_list:
  324. if arg.has_definition():
  325. arg.generate_python_def(code_generator)
  326. code_generator.append_line(
  327. '%s = %s(%s)' % (
  328. code_generator.get_result_name(self),
  329. self.target.generate_python_use(code_generator),
  330. ', '.join([arg.generate_python_use(code_generator) for arg in self.argument_list])))
  331. class PrintInstruction(Instruction):
  332. """An instruction that prints a value."""
  333. def __init__(self, argument):
  334. Instruction.__init__(self)
  335. self.argument = argument
  336. def has_result_impl(self):
  337. """Tells if this instruction has a result."""
  338. return False
  339. def get_children(self):
  340. """Gets this instruction's sequence of child instructions."""
  341. return [self.argument]
  342. def create(self, new_children):
  343. """Creates a new instruction of this type from the given sequence of child instructions."""
  344. arg, = new_children
  345. return PrintInstruction(arg)
  346. def generate_python_def(self, code_generator):
  347. """Generates Python code for this instruction."""
  348. if self.argument.has_definition():
  349. self.argument.generate_python_def(code_generator)
  350. code_generator.append_line(
  351. 'print(%s)' % (
  352. self.argument.generate_python_use(code_generator)))
  353. class BinaryInstruction(Instruction):
  354. """An instruction that performs a binary operation."""
  355. def __init__(self, lhs, operator, rhs):
  356. Instruction.__init__(self)
  357. self.lhs = lhs
  358. self.operator = operator
  359. self.rhs = rhs
  360. def has_definition_impl(self):
  361. """Tells if this instruction requires a definition."""
  362. return self.lhs.has_definition() or self.rhs.has_definition()
  363. def get_children(self):
  364. """Gets this instruction's sequence of child instructions."""
  365. return [self.lhs, self.rhs]
  366. def create(self, new_children):
  367. """Creates a new instruction of this type from the given sequence of child instructions."""
  368. lhs, rhs, = new_children
  369. return BinaryInstruction(lhs, self.operator, rhs)
  370. def simplify_node(self):
  371. """Applies basic simplification to this instruction only."""
  372. if isinstance(self.lhs, LiteralInstruction) and isinstance(self.rhs, LiteralInstruction):
  373. # TODO: there's probably a better way to do this than with eval.
  374. return LiteralInstruction(
  375. eval('%s %s %s' % (repr(self.lhs.literal), self.operator, repr(self.rhs.literal))))
  376. else:
  377. return self
  378. def generate_python_use(self, code_generator):
  379. """Generates a Python expression that retrieves this instruction's
  380. result. The expression is returned as a string."""
  381. return '(%s %s %s)' % (
  382. self.lhs.generate_python_use(code_generator),
  383. self.operator,
  384. self.rhs.generate_python_use(code_generator))
  385. def generate_python_def(self, code_generator):
  386. """Generates a Python statement that executes this instruction.
  387. The statement is appended immediately to the code generator."""
  388. if self.lhs.has_definition():
  389. self.lhs.generate_python_def(code_generator)
  390. if self.rhs.has_definition():
  391. self.rhs.generate_python_def(code_generator)
  392. elif self.rhs.has_definition():
  393. self.rhs.generate_python_def(code_generator)
  394. else:
  395. code_generator.append_line('pass')
  396. class UnaryInstruction(Instruction):
  397. """An instruction that performs a unary operation."""
  398. def __init__(self, operator, operand):
  399. Instruction.__init__(self)
  400. self.operator = operator
  401. self.operand = operand
  402. def has_definition_impl(self):
  403. """Tells if this instruction requires a definition."""
  404. return self.operand.has_definition()
  405. def get_children(self):
  406. """Gets this instruction's sequence of child instructions."""
  407. return [self.operand]
  408. def create(self, new_children):
  409. """Creates a new instruction of this type from the given sequence of child instructions."""
  410. operand, = new_children
  411. return UnaryInstruction(self.operator, operand)
  412. def simplify_node(self):
  413. """Applies basic simplification to this instruction only."""
  414. if isinstance(self.operand, LiteralInstruction):
  415. # TODO: there's probably a better way to do this than with eval.
  416. return LiteralInstruction(
  417. eval('%s %s' % (self.operator, repr(self.operand.literal))))
  418. else:
  419. return self
  420. def generate_python_use(self, code_generator):
  421. """Generates a Python expression that retrieves this instruction's
  422. result. The expression is returned as a string."""
  423. return '(%s %s)' % (
  424. self.operator,
  425. self.operand.generate_python_use(code_generator))
  426. def generate_python_def(self, code_generator):
  427. """Generates a Python statement that executes this instruction.
  428. The statement is appended immediately to the code generator."""
  429. if self.operand.has_definition():
  430. self.operand.generate_python_def(code_generator)
  431. else:
  432. code_generator.append_line('pass')
  433. class LoopInstruction(VoidInstruction):
  434. """Represents a loop-instruction, which loops until broken."""
  435. def __init__(self, body):
  436. VoidInstruction.__init__(self)
  437. self.body = body
  438. def get_children(self):
  439. """Gets this instruction's sequence of child instructions."""
  440. return [self.body]
  441. def create(self, new_children):
  442. """Creates a new instruction of this type from the given sequence of child instructions."""
  443. body, = new_children
  444. return LoopInstruction(body)
  445. def generate_python_def(self, code_generator):
  446. """Generates Python code for this instruction."""
  447. code_generator.append_line('while 1:')
  448. code_generator.increase_indentation()
  449. self.body.generate_python_def(code_generator)
  450. code_generator.decrease_indentation()
  451. class BreakInstruction(VoidInstruction):
  452. """Represents a break-instruction."""
  453. def generate_python_def(self, code_generator):
  454. """Generates Python code for this instruction."""
  455. code_generator.append_line('break')
  456. class ContinueInstruction(VoidInstruction):
  457. """Represents a continue-instruction."""
  458. def generate_python_def(self, code_generator):
  459. """Generates Python code for this instruction."""
  460. code_generator.append_line('continue')
  461. class CompoundInstruction(Instruction):
  462. """Represents an instruction that evaluates two other instructions
  463. in order, and returns the second instruction's result."""
  464. def __init__(self, first, second):
  465. Instruction.__init__(self)
  466. self.first = first
  467. self.second = second
  468. def has_result_impl(self):
  469. """Tells if this instruction has a result."""
  470. return self.second.has_result() or self.first.has_result()
  471. def get_children(self):
  472. """Gets this instruction's sequence of child instructions."""
  473. return [self.first, self.second]
  474. def create(self, new_children):
  475. """Creates a new instruction of this type from the given sequence of child instructions."""
  476. first, second = new_children
  477. return CompoundInstruction(first, second)
  478. def simplify_node(self):
  479. """Applies basic simplification to this instruction and its children."""
  480. if not self.first.has_definition() and (
  481. not self.first.has_result() or self.second.has_result()):
  482. return self.second
  483. elif (not self.second.has_definition()) and (not self.second.has_result()):
  484. return self.first
  485. else:
  486. return self
  487. def generate_python_def(self, code_generator):
  488. """Generates Python code for this instruction."""
  489. if self.second.has_result():
  490. self.first.generate_python_def(code_generator)
  491. code_generator.append_move_definition(self, self.second)
  492. elif self.first.has_result():
  493. code_generator.append_move_definition(self, self.first)
  494. self.second.generate_python_def(code_generator)
  495. else:
  496. self.first.generate_python_def(code_generator)
  497. self.second.generate_python_def(code_generator)
  498. class LiteralInstruction(Instruction):
  499. """Represents an integer, floating-point, string or Boolean literal."""
  500. def __init__(self, literal):
  501. Instruction.__init__(self)
  502. self.literal = literal
  503. def has_definition_impl(self):
  504. """Tells if this instruction requires a definition."""
  505. return False
  506. def get_children(self):
  507. """Gets this instruction's sequence of child instructions."""
  508. return []
  509. def create(self, new_children):
  510. """Creates a new instruction of this type from the given sequence of child instructions."""
  511. return self
  512. def generate_python_use(self, code_generator):
  513. """Generates a Python expression that retrieves this instruction's
  514. result. The expression is returned as a string."""
  515. return repr(self.literal)
  516. class DictionaryLiteralInstruction(Instruction):
  517. """Constructs a dictionary literal."""
  518. def __init__(self, key_value_pairs):
  519. Instruction.__init__(self)
  520. self.key_value_pairs = key_value_pairs
  521. def get_children(self):
  522. """Gets this instruction's sequence of child instructions."""
  523. return [val for _, val in self.key_value_pairs]
  524. def create(self, new_children):
  525. """Creates a new instruction of this type from the given sequence of child instructions."""
  526. keys = [k for k, _ in self.key_value_pairs]
  527. return DictionaryLiteralInstruction(zip(keys, new_children))
  528. def has_definition_impl(self):
  529. """Tells if this instruction requires a definition."""
  530. return any(
  531. [key.has_definition() or val.has_definition()
  532. for key, val in self.key_value_pairs])
  533. def simplify(self):
  534. """Applies basic simplification to this instruction and its children."""
  535. return DictionaryLiteralInstruction(
  536. [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
  537. def generate_dictionary_expr(self, code_generator):
  538. """Generates an expression that creates this dictionary."""
  539. return '{%s}' % ', '.join(
  540. ['%s : %s' % (
  541. key.generate_python_use(code_generator),
  542. val.generate_python_use(code_generator))
  543. for key, val in self.key_value_pairs])
  544. def generate_python_def(self, code_generator):
  545. """Generates a Python statement that executes this instruction.
  546. The statement is appended immediately to the code generator."""
  547. if self.has_definition():
  548. for key, val in self.key_value_pairs:
  549. if key.has_definition():
  550. key.generate_python_def(code_generator)
  551. if val.has_definition():
  552. val.generate_python_def(code_generator)
  553. code_generator.append_line('%s = %s' % (
  554. code_generator.get_result_name(self),
  555. self.generate_dictionary_expr(code_generator)))
  556. else:
  557. code_generator.append_line('pass')
  558. def generate_python_use(self, code_generator):
  559. """Generates a Python expression that retrieves this instruction's
  560. result. The expression is returned as a string."""
  561. if self.has_definition():
  562. return code_generator.get_result_name(self)
  563. else:
  564. return self.generate_dictionary_expr(code_generator)
  565. class StateInstruction(Instruction):
  566. """An instruction that accesses the modelverse state."""
  567. def get_opcode(self):
  568. """Gets the opcode for this state instruction."""
  569. raise NotImplementedError()
  570. def get_arguments(self):
  571. """Gets this state instruction's argument list."""
  572. raise NotImplementedError()
  573. def get_children(self):
  574. """Gets this instruction's sequence of child instructions."""
  575. return self.get_arguments()
  576. def create(self, new_children):
  577. """Creates a new instruction of this type from the given sequence of child instructions."""
  578. return type(self)(*new_children)
  579. def generate_python_def(self, code_generator):
  580. """Generates a Python statement that executes this instruction.
  581. The statement is appended immediately to the code generator."""
  582. args = self.get_arguments()
  583. for arg_i in args:
  584. if arg_i.has_definition():
  585. arg_i.generate_python_def(code_generator)
  586. code_generator.append_state_definition(self, self.get_opcode(), args)
  587. class RunGeneratorFunctionInstruction(StateInstruction):
  588. """An instruction that runs a generator function."""
  589. def __init__(self, function, argument_dict):
  590. StateInstruction.__init__(self)
  591. self.function = function
  592. self.argument_dict = argument_dict
  593. def get_opcode(self):
  594. """Gets the opcode for this state instruction."""
  595. return "CALL_KWARGS"
  596. def get_arguments(self):
  597. """Gets this state instruction's argument list."""
  598. return [self.function, self.argument_dict]
  599. class RunTailGeneratorFunctionInstruction(StateInstruction):
  600. """An instruction that runs a generator function."""
  601. def __init__(self, function, argument_dict):
  602. StateInstruction.__init__(self)
  603. self.function = function
  604. self.argument_dict = argument_dict
  605. def get_opcode(self):
  606. """Gets the opcode for this state instruction."""
  607. return "TAIL_CALL_KWARGS"
  608. def get_arguments(self):
  609. """Gets this state instruction's argument list."""
  610. return [self.function, self.argument_dict]
  611. class VariableName(object):
  612. """A data structure that unifies names across instructions that access the
  613. same variable."""
  614. def __init__(self, name):
  615. self.name = name
  616. def get_result_name_override(self, _):
  617. """Gets a value that overrides the code generator's result name for this
  618. instruction if it is not None."""
  619. return self.name
  620. class VariableInstruction(Instruction):
  621. """A base class for instructions that access variables."""
  622. def __init__(self, name):
  623. Instruction.__init__(self)
  624. if isinstance(name, str) or isinstance(name, unicode) or name is None:
  625. self.name = VariableName(name)
  626. else:
  627. self.name = name
  628. def get_children(self):
  629. """Gets this instruction's sequence of child instructions."""
  630. raise NotImplementedError()
  631. def create(self, new_children):
  632. """Creates a new instruction of this type from the given sequence of child instructions."""
  633. raise NotImplementedError()
  634. def get_result_name_override(self, code_generator):
  635. """Gets a value that overrides the code generator's result name for this
  636. instruction if it is not None."""
  637. return code_generator.get_result_name(self.name)
  638. class LocalInstruction(VariableInstruction):
  639. """A base class for instructions that access local variables."""
  640. def get_children(self):
  641. """Gets this instruction's sequence of child instructions."""
  642. raise NotImplementedError()
  643. def create(self, new_children):
  644. """Creates a new instruction of this type from the given sequence of child instructions."""
  645. raise NotImplementedError()
  646. def create_load(self):
  647. """Creates an instruction that loads the variable referenced by this instruction."""
  648. return LoadLocalInstruction(self.name)
  649. def create_store(self, value):
  650. """Creates an instruction that stores the given value in the variable referenced
  651. by this instruction."""
  652. return StoreLocalInstruction(self.name, value)
  653. class StoreLocalInstruction(LocalInstruction):
  654. """An instruction that stores a value in a local variable."""
  655. def __init__(self, name, value):
  656. LocalInstruction.__init__(self, name)
  657. self.value = value
  658. def get_children(self):
  659. """Gets this instruction's sequence of child instructions."""
  660. return [self.value]
  661. def create(self, new_children):
  662. """Creates a new instruction of this type from the given sequence of child instructions."""
  663. val, = new_children
  664. return StoreLocalInstruction(self.name, val)
  665. def generate_python_def(self, code_generator):
  666. """Generates a Python statement that executes this instruction.
  667. The statement is appended immediately to the code generator."""
  668. code_generator.append_move_definition(self, self.value)
  669. class LoadLocalInstruction(LocalInstruction):
  670. """An instruction that loads a value from a local variable."""
  671. def has_definition_impl(self):
  672. """Tells if this instruction requires a definition."""
  673. return False
  674. def get_children(self):
  675. """Gets this instruction's sequence of child instructions."""
  676. return []
  677. def create(self, new_children):
  678. """Creates a new instruction of this type from the given sequence of child instructions."""
  679. return self
  680. class DefineFunctionInstruction(VariableInstruction):
  681. """An instruction that defines a function."""
  682. def __init__(self, name, parameter_list, body):
  683. VariableInstruction.__init__(self, name)
  684. self.parameter_list = parameter_list
  685. self.body = body
  686. def get_children(self):
  687. """Gets this instruction's sequence of child instructions."""
  688. return [self.body]
  689. def create(self, new_children):
  690. """Creates a new instruction of this type from the given sequence of child instructions."""
  691. body, = new_children
  692. return DefineFunctionInstruction(self.name, self.parameter_list, body)
  693. def generate_python_def(self, code_generator):
  694. """Generates a Python statement that executes this instruction.
  695. The statement is appended immediately to the code generator."""
  696. code_generator.append_line('def %s(%s):' % (
  697. code_generator.get_result_name(self), ', '.join(self.parameter_list)))
  698. code_generator.increase_indentation()
  699. self.body.generate_python_def(code_generator)
  700. code_generator.decrease_indentation()
  701. class LocalExistsInstruction(LocalInstruction):
  702. """An instruction that checks if a local variable exists."""
  703. def has_definition_impl(self):
  704. """Tells if this instruction requires a definition."""
  705. return False
  706. def get_children(self):
  707. """Gets this instruction's sequence of child instructions."""
  708. return []
  709. def create(self, new_children):
  710. """Creates a new instruction of this type from the given sequence of child instructions."""
  711. return self
  712. def generate_python_use(self, code_generator):
  713. """Generates a Python expression that retrieves this instruction's
  714. result. The expression is returned as a string."""
  715. return "'%s' in locals()" % self.get_result_name_override(code_generator)
  716. class LoadGlobalInstruction(VariableInstruction):
  717. """An instruction that loads a value from a global variable."""
  718. def has_definition_impl(self):
  719. """Tells if this instruction requires a definition."""
  720. return False
  721. def get_children(self):
  722. """Gets this instruction's sequence of child instructions."""
  723. return []
  724. def create(self, new_children):
  725. """Creates a new instruction of this type from the given sequence of child instructions."""
  726. return self
  727. class LoadIndexInstruction(Instruction):
  728. """An instruction that produces a value by indexing a specified expression with
  729. a given key."""
  730. def __init__(self, indexed, key):
  731. Instruction.__init__(self)
  732. self.indexed = indexed
  733. self.key = key
  734. def has_definition_impl(self):
  735. """Tells if this instruction requires a definition."""
  736. return False
  737. def get_children(self):
  738. """Gets this instruction's sequence of child instructions."""
  739. return [self.indexed, self.key]
  740. def create(self, new_children):
  741. """Creates a new instruction of this type from the given sequence of child instructions."""
  742. indexed, key = new_children
  743. return LoadIndexInstruction(indexed, key)
  744. def generate_python_use(self, code_generator):
  745. """Generates a Python expression that retrieves this instruction's
  746. result. The expression is returned as a string."""
  747. if self.indexed.has_definition():
  748. self.indexed.generate_python_def(code_generator)
  749. if self.key.has_definition():
  750. self.key.generate_python_def(code_generator)
  751. return "%s[%s]" % (
  752. self.indexed.generate_python_use(code_generator),
  753. self.key.generate_python_use(code_generator))
  754. class LoadMemberInstruction(Instruction):
  755. """An instruction that produces a value by loading a member from a container."""
  756. def __init__(self, container, member_name):
  757. Instruction.__init__(self)
  758. self.container = container
  759. self.member_name = member_name
  760. def has_definition_impl(self):
  761. """Tells if this instruction requires a definition."""
  762. return self.container.has_definition()
  763. def get_children(self):
  764. """Gets this instruction's sequence of child instructions."""
  765. return [self.container]
  766. def create(self, new_children):
  767. """Creates a new instruction of this type from the given sequence of child instructions."""
  768. container, = new_children
  769. return LoadMemberInstruction(container, self.member_name)
  770. def generate_python_def(self, code_generator):
  771. """Generates a Python statement that executes this instruction.
  772. The statement is appended immediately to the code generator."""
  773. self.container.generate_python_def(code_generator)
  774. def generate_python_use(self, code_generator):
  775. """Generates a Python expression that retrieves this instruction's
  776. result. The expression is returned as a string."""
  777. return "%s.%s" % (
  778. self.container.generate_python_use(code_generator),
  779. self.member_name)
  780. class StoreMemberInstruction(Instruction):
  781. """An instruction that stores a value in a container member."""
  782. def __init__(self, container, member_name, value):
  783. Instruction.__init__(self)
  784. self.container = container
  785. self.member_name = member_name
  786. self.value = value
  787. def has_definition_impl(self):
  788. """Tells if this instruction requires a definition."""
  789. return True
  790. def has_result_impl(self):
  791. """Tells if this instruction computes a result."""
  792. return False
  793. def get_children(self):
  794. """Gets this instruction's sequence of child instructions."""
  795. return [self.container, self.value]
  796. def create(self, new_children):
  797. """Creates a new instruction of this type from the given sequence of child instructions."""
  798. container, value = new_children
  799. return StoreMemberInstruction(container, self.member_name, value)
  800. def generate_python_def(self, code_generator):
  801. """Generates a Python statement that executes this instruction.
  802. The statement is appended immediately to the code generator."""
  803. if self.container.has_definition():
  804. self.container.generate_python_def(code_generator)
  805. code_generator.append_line('%s.%s = %s' % (
  806. self.container.generate_python_use(code_generator),
  807. self.member_name,
  808. self.value.generate_python_use(code_generator)))
  809. class NopInstruction(Instruction):
  810. """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
  811. def has_result_impl(self):
  812. """Tells if this instruction computes a result."""
  813. return False
  814. def get_children(self):
  815. """Gets this instruction's sequence of child instructions."""
  816. return []
  817. def create(self, new_children):
  818. """Creates a new instruction of this type from the given sequence of child instructions."""
  819. return self
  820. def generate_python_def(self, code_generator):
  821. """Generates a Python statement that executes this instruction.
  822. The statement is appended immediately to the code generator."""
  823. code_generator.append_line('yield %s' % repr(NOP_LITERAL))
  824. class ReadValueInstruction(StateInstruction):
  825. """An instruction that reads a value from a node."""
  826. def __init__(self, node_id):
  827. StateInstruction.__init__(self)
  828. self.node_id = node_id
  829. def simplify_node(self):
  830. """Applies basic simplification to this instruction only."""
  831. if isinstance(self.node_id, CreateNodeWithValueInstruction):
  832. return self.node_id.value
  833. else:
  834. return self
  835. def get_opcode(self):
  836. """Gets the opcode for this state instruction."""
  837. return "RV"
  838. def get_arguments(self):
  839. """Gets this state instruction's argument list."""
  840. return [self.node_id]
  841. class ReadDictionaryValueInstruction(StateInstruction):
  842. """An instruction that reads a dictionary value."""
  843. def __init__(self, node_id, key):
  844. StateInstruction.__init__(self)
  845. self.node_id = node_id
  846. self.key = key
  847. def get_opcode(self):
  848. """Gets the opcode for this state instruction."""
  849. return "RD"
  850. def get_arguments(self):
  851. """Gets this state instruction's argument list."""
  852. return [self.node_id, self.key]
  853. class ReadDictionaryEdgeInstruction(StateInstruction):
  854. """An instruction that reads a dictionary edge."""
  855. def __init__(self, node_id, key):
  856. StateInstruction.__init__(self)
  857. self.node_id = node_id
  858. self.key = key
  859. def get_opcode(self):
  860. """Gets the opcode for this state instruction."""
  861. return "RDE"
  862. def get_arguments(self):
  863. """Gets this state instruction's argument list."""
  864. return [self.node_id, self.key]
  865. class ReadEdgeInstruction(StateInstruction):
  866. """An instruction that reads an edge."""
  867. def __init__(self, node_id):
  868. StateInstruction.__init__(self)
  869. self.node_id = node_id
  870. def get_opcode(self):
  871. """Gets the opcode for this state instruction."""
  872. return "RE"
  873. def get_arguments(self):
  874. """Gets this state instruction's argument list."""
  875. return [self.node_id]
  876. class ReadOutgoingEdgesInstruction(StateInstruction):
  877. """An instruction that reads all outgoing edges for a node."""
  878. def __init__(self, node_id):
  879. StateInstruction.__init__(self)
  880. self.node_id = node_id
  881. def get_opcode(self):
  882. """Gets the opcode for this state instruction."""
  883. return "RO"
  884. def get_arguments(self):
  885. """Gets this state instruction's argument list."""
  886. return [self.node_id]
  887. class ReadIncomingEdgesInstruction(StateInstruction):
  888. """An instruction that reads all incoming edges for a node."""
  889. def __init__(self, node_id):
  890. StateInstruction.__init__(self)
  891. self.node_id = node_id
  892. def get_opcode(self):
  893. """Gets the opcode for this state instruction."""
  894. return "RI"
  895. def get_arguments(self):
  896. """Gets this state instruction's argument list."""
  897. return [self.node_id]
  898. class CreateNodeInstruction(StateInstruction):
  899. """An instruction that creates an empty node."""
  900. def get_opcode(self):
  901. """Gets the opcode for this state instruction."""
  902. return "CN"
  903. def get_arguments(self):
  904. """Gets this state instruction's argument list."""
  905. return []
  906. class CreateNodeWithValueInstruction(StateInstruction):
  907. """An instruction that creates a node with a given value."""
  908. def __init__(self, value):
  909. StateInstruction.__init__(self)
  910. self.value = value
  911. def get_opcode(self):
  912. """Gets the opcode for this state instruction."""
  913. return "CNV"
  914. def get_arguments(self):
  915. """Gets this state instruction's argument list."""
  916. return [self.value]
  917. class CreateEdgeInstruction(StateInstruction):
  918. """An instruction that creates an edge."""
  919. def __init__(self, source_id, target_id):
  920. StateInstruction.__init__(self)
  921. self.source_id = source_id
  922. self.target_id = target_id
  923. def get_opcode(self):
  924. """Gets the opcode for this state instruction."""
  925. return "CE"
  926. def get_arguments(self):
  927. """Gets this state instruction's argument list."""
  928. return [self.source_id, self.target_id]
  929. class CreateDictionaryEdgeInstruction(StateInstruction):
  930. """An instruction that creates a dictionary edge."""
  931. def __init__(self, source_id, key, target_id):
  932. StateInstruction.__init__(self)
  933. self.source_id = source_id
  934. self.key = key
  935. self.target_id = target_id
  936. def get_opcode(self):
  937. """Gets the opcode for this state instruction."""
  938. return "CD"
  939. def get_arguments(self):
  940. """Gets this state instruction's argument list."""
  941. return [self.source_id, self.key, self.target_id]
  942. class DeleteNodeInstruction(StateInstruction):
  943. """An instruction that deletes a node."""
  944. def __init__(self, node_id):
  945. StateInstruction.__init__(self)
  946. self.node_id = node_id
  947. def has_result(self):
  948. """Tells if this instruction computes a result."""
  949. return False
  950. def get_opcode(self):
  951. """Gets the opcode for this state instruction."""
  952. return "DN"
  953. def get_arguments(self):
  954. """Gets this state instruction's argument list."""
  955. return [self.node_id]
  956. class DeleteEdgeInstruction(StateInstruction):
  957. """An instruction that deletes an edge."""
  958. def __init__(self, edge_id):
  959. StateInstruction.__init__(self)
  960. self.edge_id = edge_id
  961. def has_result(self):
  962. """Tells if this instruction computes a result."""
  963. return False
  964. def get_opcode(self):
  965. """Gets the opcode for this state instruction."""
  966. return "DE"
  967. def get_arguments(self):
  968. """Gets this state instruction's argument list."""
  969. return [self.edge_id]
  970. def create_block(*statements):
  971. """Creates a block-statement from the given list of statements."""
  972. length = len(statements)
  973. if length == 0:
  974. return EmptyInstruction()
  975. elif length == 1:
  976. return statements[0]
  977. else:
  978. return CompoundInstruction(
  979. statements[0],
  980. create_block(*statements[1:]))
  981. def create_jit_call(target, named_arguments, kwargs):
  982. """Creates a call that abides by the JIT's calling convention."""
  983. # A JIT call looks like this:
  984. #
  985. # target = ...
  986. # arg_dict = { ... }
  987. # arg_dict.update(kwargs)
  988. # result, = yield [("CALL_KWARGS", [target, arg_dict])]
  989. results = []
  990. if target.has_definition():
  991. target_tmp = StoreLocalInstruction(None, target)
  992. results.append(target_tmp)
  993. target = target_tmp.create_load()
  994. arg_dict = StoreLocalInstruction(
  995. None,
  996. DictionaryLiteralInstruction(
  997. [(LiteralInstruction(key), val) for key, val in named_arguments]))
  998. results.append(arg_dict)
  999. results.append(
  1000. CallInstruction(
  1001. LoadMemberInstruction(arg_dict.create_load(), 'update'),
  1002. [kwargs]))
  1003. return CompoundInstruction(
  1004. create_block(*results),
  1005. RunGeneratorFunctionInstruction(
  1006. target, arg_dict.create_load()))
  1007. def with_debug_info_trace(instruction, debug_info, function_name):
  1008. """Prepends the given instruction with a tracing instruction that prints
  1009. the given debug information and function name."""
  1010. if debug_info is None and function_name is None:
  1011. return instruction
  1012. else:
  1013. if debug_info is None:
  1014. debug_info = 'unknown location '
  1015. if function_name is None:
  1016. function_name = 'unknown function'
  1017. return create_block(
  1018. PrintInstruction(
  1019. LiteralInstruction('TRACE: %s(%s, JIT)' % (debug_info, function_name))),
  1020. instruction)
  1021. def map_and_simplify(function, instruction):
  1022. """Applies the given mapping function to every instruction in the tree
  1023. that has the given instruction as root, and simplifies it on-the-fly.
  1024. This is at least as powerful as first mapping and then simplifying, as
  1025. maps and simplifications are interspersed."""
  1026. # Let's just agree to disagree on map vs list comprehensions, pylint.
  1027. # pylint: disable=I0011,W0141
  1028. return function(
  1029. instruction.create(
  1030. map(map_and_simplify, instruction.get_children()))).simplify_node()
  1031. if __name__ == "__main__":
  1032. example_tree = SelectInstruction(
  1033. LiteralInstruction(True),
  1034. LoopInstruction(
  1035. CompoundInstruction(
  1036. BreakInstruction(),
  1037. CompoundInstruction(
  1038. EmptyInstruction(),
  1039. ContinueInstruction()
  1040. )
  1041. )
  1042. ),
  1043. ReturnInstruction(
  1044. EmptyInstruction()))
  1045. print(example_tree.simplify())