tree_ir.py 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277
  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 create_new_local_node(local_variable, connected_node, edge_variable=None):
  1008. """Creates a local node that is the backing storage for a local variable.
  1009. This node is connected to a given node to make sure it's not perceived
  1010. as dead by the GC. The newly created node is stored in the given
  1011. local variable. The edge's id can also optionally be stored in a variable."""
  1012. local_store = StoreLocalInstruction(local_variable, CreateNodeInstruction())
  1013. create_edge = CreateEdgeInstruction(local_store.create_load(), connected_node)
  1014. if edge_variable is not None:
  1015. create_edge = StoreLocalInstruction(edge_variable, create_edge)
  1016. return create_block(local_store, create_edge)
  1017. def with_debug_info_trace(instruction, debug_info, function_name):
  1018. """Prepends the given instruction with a tracing instruction that prints
  1019. the given debug information and function name."""
  1020. if debug_info is None and function_name is None:
  1021. return instruction
  1022. else:
  1023. if debug_info is None:
  1024. debug_info = 'unknown location '
  1025. if function_name is None:
  1026. function_name = 'unknown function'
  1027. return create_block(
  1028. PrintInstruction(
  1029. LiteralInstruction('TRACE: %s(%s, JIT)' % (debug_info, function_name))),
  1030. instruction)
  1031. def map_and_simplify(function, instruction):
  1032. """Applies the given mapping function to every instruction in the tree
  1033. that has the given instruction as root, and simplifies it on-the-fly.
  1034. This is at least as powerful as first mapping and then simplifying, as
  1035. maps and simplifications are interspersed."""
  1036. # Let's just agree to disagree on map vs list comprehensions, pylint.
  1037. # pylint: disable=I0011,W0141
  1038. return function(
  1039. instruction.create(
  1040. map(map_and_simplify, instruction.get_children()))).simplify_node()
  1041. if __name__ == "__main__":
  1042. example_tree = SelectInstruction(
  1043. LiteralInstruction(True),
  1044. LoopInstruction(
  1045. CompoundInstruction(
  1046. BreakInstruction(),
  1047. CompoundInstruction(
  1048. EmptyInstruction(),
  1049. ContinueInstruction()
  1050. )
  1051. )
  1052. ),
  1053. ReturnInstruction(
  1054. EmptyInstruction()))
  1055. print(example_tree.simplify())