tree_ir.py 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  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. pass
  34. def has_result(self):
  35. """Tells if this instruction computes a result."""
  36. return True
  37. def has_definition(self):
  38. """Tells if this instruction requires a definition."""
  39. return True
  40. def get_result_name_override(self, code_generator):
  41. """Gets a value that overrides the code generator's result name for this
  42. instruction if it is not None."""
  43. return None
  44. def generate_python_def(self, code_generator):
  45. """Generates a Python statement that executes this instruction.
  46. The statement is appended immediately to the code generator."""
  47. if self.has_definition():
  48. raise NotImplementedError()
  49. else:
  50. code_generator.append_line('pass')
  51. def generate_python_use(self, code_generator):
  52. """Generates a Python expression that retrieves this instruction's
  53. result. The expression is returned as a string."""
  54. if self.has_result():
  55. return code_generator.get_result_name(self)
  56. else:
  57. return 'None'
  58. def simplify(self):
  59. """Applies basic simplification to this instruction and its children."""
  60. return self
  61. def __str__(self):
  62. code_generator = PythonGenerator()
  63. self.generate_python_def(code_generator)
  64. return str(code_generator)
  65. class PythonGenerator(object):
  66. """Generates Python code from instructions."""
  67. def __init__(self):
  68. self.code = []
  69. self.indentation_string = ' ' * 4
  70. self.indentation = 0
  71. self.result_value_dict = {}
  72. def append(self, text):
  73. """Appends the given string to this code generator."""
  74. self.code.append(text)
  75. def append_indentation(self):
  76. """Appends indentation to the code generator."""
  77. self.append(self.indentation_string * self.indentation)
  78. def append_line(self, line=None):
  79. """Appends the indentation string followed by the given string (if any)
  80. and a newline to the code generator."""
  81. self.append_indentation()
  82. if line is not None:
  83. self.append(line)
  84. self.append('\n')
  85. def increase_indentation(self):
  86. """Increases the code generator's indentation by one indent."""
  87. self.indentation += 1
  88. def decrease_indentation(self):
  89. """Decreases the code generator's indentation by one indent."""
  90. self.indentation -= 1
  91. def get_result_name(self, instruction, advised_name=None):
  92. """Gets the name of the given instruction's result variable."""
  93. if instruction not in self.result_value_dict:
  94. override_name = instruction.get_result_name_override(self)
  95. if override_name is not None:
  96. self.result_value_dict[instruction] = override_name
  97. elif advised_name is not None:
  98. self.result_value_dict[instruction] = advised_name
  99. else:
  100. self.result_value_dict[instruction] = \
  101. 'tmp' + str(len(self.result_value_dict))
  102. return self.result_value_dict[instruction]
  103. def append_definition(self, lhs, rhs):
  104. """Defines the first instruction's result variable as the second
  105. instruction's result."""
  106. self.append_line(
  107. self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
  108. def append_move_definition(self, lhs, rhs):
  109. """First defines the second instruction, then defines the first
  110. instruction as the result of the second."""
  111. if rhs.has_definition():
  112. # Retrieve the result name for the lhs.
  113. lhs_result_name = self.get_result_name(lhs)
  114. # Encourage the rhs to take on the same result name as the lhs.
  115. rhs_result_name = self.get_result_name(rhs, lhs_result_name)
  116. # Generate the rhs' definition.
  117. rhs.generate_python_def(self)
  118. # Only perform an assignment if it's truly necessary.
  119. if lhs_result_name != rhs_result_name:
  120. self.append_definition(lhs, rhs)
  121. else:
  122. self.append_definition(lhs, rhs)
  123. def append_state_definition(self, lhs, opcode, args):
  124. """Appends a definition that queries the modelverse state."""
  125. self.append_line(
  126. "%s, = yield [('%s', [%s])]" % (
  127. self.get_result_name(lhs),
  128. opcode,
  129. ', '.join([arg_i.generate_python_use(self) for arg_i in args])))
  130. def __str__(self):
  131. return ''.join(self.code)
  132. class VoidInstruction(Instruction):
  133. """A base class for instructions that do not return a value."""
  134. def has_result(self):
  135. """Tells if this instruction computes a result."""
  136. return False
  137. class EmptyInstruction(VoidInstruction):
  138. """Represents the empty instruction, which does nothing."""
  139. def has_definition(self):
  140. """Tells if this instruction requires a definition."""
  141. return False
  142. class SelectInstruction(Instruction):
  143. """Represents a select-instruction: an instruction that defines one of two
  144. child instructions, and sets its result to the defined child's result."""
  145. def __init__(self, condition, if_clause, else_clause):
  146. Instruction.__init__(self)
  147. self.condition = condition
  148. self.if_clause = if_clause
  149. self.else_clause = else_clause
  150. def has_result(self):
  151. """Tells if this instruction computes a result."""
  152. return self.if_clause.has_result() or self.else_clause.has_result()
  153. def simplify(self):
  154. """Applies basic simplification to this instruction and its children."""
  155. simple_cond = self.condition.simplify()
  156. simple_if = self.if_clause.simplify()
  157. simple_else = self.else_clause.simplify()
  158. if isinstance(simple_cond, LiteralInstruction):
  159. return simple_if if simple_cond.literal else simple_else
  160. else:
  161. return SelectInstruction(simple_cond, simple_if, simple_else)
  162. def generate_python_def(self, code_generator):
  163. """Generates Python code for this instruction."""
  164. if_has_result = self.has_result()
  165. if self.condition.has_definition():
  166. self.condition.generate_python_def(code_generator)
  167. code_generator.append_line(
  168. 'if ' + self.condition.generate_python_use(code_generator) + ':')
  169. code_generator.increase_indentation()
  170. if if_has_result:
  171. code_generator.append_move_definition(self, self.if_clause)
  172. else:
  173. self.if_clause.generate_python_def(code_generator)
  174. code_generator.decrease_indentation()
  175. else_has_def = self.else_clause.has_definition()
  176. if else_has_def or if_has_result:
  177. code_generator.append_line('else:')
  178. code_generator.increase_indentation()
  179. if if_has_result:
  180. code_generator.append_move_definition(self, self.else_clause)
  181. else:
  182. self.else_clause.generate_python_def(code_generator)
  183. code_generator.decrease_indentation()
  184. class ReturnInstruction(VoidInstruction):
  185. """Represents a return-instruction."""
  186. def __init__(self, value):
  187. VoidInstruction.__init__(self)
  188. self.value = value
  189. def simplify(self):
  190. """Applies basic simplification to this instruction and its children."""
  191. return ReturnInstruction(self.value.simplify())
  192. def generate_python_def(self, code_generator):
  193. """Generates Python code for this instruction."""
  194. if self.value.has_definition():
  195. self.value.generate_python_def(code_generator)
  196. code_generator.append_line(
  197. 'raise PrimitiveFinished(' +
  198. self.value.generate_python_use(code_generator) +
  199. ')')
  200. class RaiseInstruction(VoidInstruction):
  201. """An instruction that raises an error."""
  202. def __init__(self, value):
  203. VoidInstruction.__init__(self)
  204. self.value = value
  205. def simplify(self):
  206. """Applies basic simplification to this instruction and its children."""
  207. return RaiseInstruction(self.value.simplify())
  208. def generate_python_def(self, code_generator):
  209. """Generates Python code for this instruction."""
  210. self.value.generate_python_def(code_generator)
  211. code_generator.append_line(
  212. 'raise ' + self.value.generate_python_use(code_generator))
  213. class CallInstruction(Instruction):
  214. """An instruction that performs a simple call."""
  215. def __init__(self, target, argument_list):
  216. Instruction.__init__(self)
  217. self.target = target
  218. self.argument_list = argument_list
  219. def simplify(self):
  220. """Applies basic simplification to this instruction and its children."""
  221. return CallInstruction(
  222. self.target.simplify(),
  223. [arg.simplify() for arg in self.argument_list])
  224. def generate_python_def(self, code_generator):
  225. """Generates Python code for this instruction."""
  226. if self.target.has_definition():
  227. self.target.generate_python_def(code_generator)
  228. for arg in self.argument_list:
  229. if arg.has_definition():
  230. arg.generate_python_def(code_generator)
  231. code_generator.append_line(
  232. '%s = %s(%s)' % (
  233. code_generator.get_result_name(self),
  234. self.target.generate_python_use(code_generator),
  235. ', '.join([arg.generate_python_use(code_generator) for arg in self.argument_list])))
  236. class JitCallInstruction(Instruction):
  237. """An instruction that calls a jitted function."""
  238. def __init__(self, target, named_args, kwarg):
  239. Instruction.__init__(self)
  240. self.target = target
  241. self.named_args = named_args
  242. self.kwarg = kwarg
  243. def simplify(self):
  244. """Applies basic simplification to this instruction and its children."""
  245. return JitCallInstruction(
  246. self.target.simplify(),
  247. [(param_name, arg.simplify()) for param_name, arg in self.named_args],
  248. self.kwarg.simplify())
  249. def generate_python_def(self, code_generator):
  250. """Generates Python code for this instruction."""
  251. if self.target.has_definition():
  252. self.target.generate_python_def(code_generator)
  253. arg_list = []
  254. for param_name, arg in self.named_args:
  255. if arg.has_definition():
  256. arg.generate_python_def(code_generator)
  257. arg_list.append(
  258. '%s=%s' % (param_name, arg.generate_python_use(code_generator)))
  259. if self.kwarg.has_definition():
  260. self.kwarg.generate_python_def(code_generator)
  261. arg_list.append(
  262. '**%s' % self.kwarg.generate_python_use(code_generator))
  263. own_name = code_generator.get_result_name(self)
  264. code_generator.append_line('try:')
  265. code_generator.increase_indentation()
  266. code_generator.append_line(
  267. '%s_gen = %s(%s)' % (
  268. own_name,
  269. self.target.generate_python_use(code_generator),
  270. ', '.join(arg_list)))
  271. code_generator.append_line('%s_inp = None' % own_name)
  272. code_generator.append_line('while 1:')
  273. code_generator.increase_indentation()
  274. code_generator.append_line(
  275. '%s_inp = yield %s_gen.send(%s_inp)' % (own_name, own_name, own_name))
  276. code_generator.decrease_indentation()
  277. code_generator.decrease_indentation()
  278. code_generator.append_line('except PrimitiveFinished as %s_ex:' % own_name)
  279. code_generator.increase_indentation()
  280. code_generator.append_line('%s = %s_ex.result' % (own_name, own_name))
  281. code_generator.decrease_indentation()
  282. class PrintInstruction(Instruction):
  283. """An instruction that prints a value."""
  284. def __init__(self, argument):
  285. Instruction.__init__(self)
  286. self.argument = argument
  287. def has_result(self):
  288. """Tells if this instruction has a result."""
  289. return False
  290. def simplify(self):
  291. """Applies basic simplification to this instruction and its children."""
  292. return PrintInstruction(self.argument.simplify())
  293. def generate_python_def(self, code_generator):
  294. """Generates Python code for this instruction."""
  295. if self.argument.has_definition():
  296. self.argument.generate_python_def(code_generator)
  297. code_generator.append_line(
  298. 'print(%s)' % (
  299. self.argument.generate_python_use(code_generator)))
  300. class BinaryInstruction(Instruction):
  301. """An instruction that performs a binary operation."""
  302. def __init__(self, lhs, operator, rhs):
  303. Instruction.__init__(self)
  304. self.lhs = lhs
  305. self.operator = operator
  306. self.rhs = rhs
  307. def has_definition(self):
  308. """Tells if this instruction requires a definition."""
  309. return self.lhs.has_definition() or self.rhs.has_definition()
  310. def simplify(self):
  311. """Applies basic simplification to this instruction and its children."""
  312. simple_lhs, simple_rhs = self.lhs.simplify(), self.rhs.simplify()
  313. return BinaryInstruction(simple_lhs, self.operator, simple_rhs)
  314. def generate_python_use(self, code_generator):
  315. """Generates a Python expression that retrieves this instruction's
  316. result. The expression is returned as a string."""
  317. return '(%s %s %s)' % (
  318. self.lhs.generate_python_use(code_generator),
  319. self.operator,
  320. self.rhs.generate_python_use(code_generator))
  321. def generate_python_def(self, code_generator):
  322. """Generates a Python statement that executes this instruction.
  323. The statement is appended immediately to the code generator."""
  324. if self.lhs.has_definition():
  325. self.lhs.generate_python_def(code_generator)
  326. if self.rhs.has_definition():
  327. self.rhs.generate_python_def(code_generator)
  328. elif self.rhs.has_definition():
  329. self.rhs.generate_python_def(code_generator)
  330. else:
  331. code_generator.append_line('pass')
  332. class UnaryInstruction(Instruction):
  333. """An instruction that performs a unary operation."""
  334. def __init__(self, operator, operand):
  335. Instruction.__init__(self)
  336. self.operator = operator
  337. self.operand = operand
  338. def has_definition(self):
  339. """Tells if this instruction requires a definition."""
  340. return self.operand.has_definition()
  341. def simplify(self):
  342. """Applies basic simplification to this instruction and its children."""
  343. simple_operand = self.operand.simplify()
  344. return UnaryInstruction(self.operator, simple_operand)
  345. def generate_python_use(self, code_generator):
  346. """Generates a Python expression that retrieves this instruction's
  347. result. The expression is returned as a string."""
  348. return '(%s %s)' % (
  349. self.operator,
  350. self.operand.generate_python_use(code_generator))
  351. def generate_python_def(self, code_generator):
  352. """Generates a Python statement that executes this instruction.
  353. The statement is appended immediately to the code generator."""
  354. if self.operand.has_definition():
  355. self.operand.generate_python_def(code_generator)
  356. else:
  357. code_generator.append_line('pass')
  358. class LoopInstruction(VoidInstruction):
  359. """Represents a loop-instruction, which loops until broken."""
  360. def __init__(self, body):
  361. VoidInstruction.__init__(self)
  362. self.body = body
  363. def simplify(self):
  364. """Applies basic simplification to this instruction and its children."""
  365. return LoopInstruction(self.body.simplify())
  366. def generate_python_def(self, code_generator):
  367. """Generates Python code for this instruction."""
  368. code_generator.append_line('while 1:')
  369. code_generator.increase_indentation()
  370. self.body.generate_python_def(code_generator)
  371. code_generator.decrease_indentation()
  372. class BreakInstruction(VoidInstruction):
  373. """Represents a break-instruction."""
  374. def generate_python_def(self, code_generator):
  375. """Generates Python code for this instruction."""
  376. code_generator.append_line('break')
  377. class ContinueInstruction(VoidInstruction):
  378. """Represents a continue-instruction."""
  379. def generate_python_def(self, code_generator):
  380. """Generates Python code for this instruction."""
  381. code_generator.append_line('continue')
  382. class CompoundInstruction(Instruction):
  383. """Represents an instruction that evaluates two other instructions
  384. in order, and returns the second instruction's result."""
  385. def __init__(self, first, second):
  386. Instruction.__init__(self)
  387. self.first = first
  388. self.second = second
  389. def has_result(self):
  390. """Tells if this instruction has a result."""
  391. return self.second.has_result() or self.first.has_result()
  392. def simplify(self):
  393. """Applies basic simplification to this instruction and its children."""
  394. simple_fst, simple_snd = self.first.simplify(), self.second.simplify()
  395. if not simple_fst.has_definition() and (
  396. not simple_fst.has_result() or simple_snd.has_result()):
  397. return simple_snd
  398. elif (not simple_snd.has_definition()) and (not simple_snd.has_result()):
  399. return simple_fst
  400. else:
  401. return CompoundInstruction(simple_fst, simple_snd)
  402. def generate_python_def(self, code_generator):
  403. """Generates Python code for this instruction."""
  404. if self.second.has_result():
  405. self.first.generate_python_def(code_generator)
  406. code_generator.append_move_definition(self, self.second)
  407. elif self.first.has_result():
  408. code_generator.append_move_definition(self, self.first)
  409. self.second.generate_python_def(code_generator)
  410. else:
  411. self.first.generate_python_def(code_generator)
  412. self.second.generate_python_def(code_generator)
  413. class LiteralInstruction(Instruction):
  414. """Represents an integer, floating-point, string or Boolean literal."""
  415. def __init__(self, literal):
  416. Instruction.__init__(self)
  417. self.literal = literal
  418. def has_definition(self):
  419. """Tells if this instruction requires a definition."""
  420. return False
  421. def generate_python_use(self, code_generator):
  422. """Generates a Python expression that retrieves this instruction's
  423. result. The expression is returned as a string."""
  424. return repr(self.literal)
  425. class DictionaryLiteralInstruction(Instruction):
  426. """Constructs a dictionary literal."""
  427. def __init__(self, key_value_pairs):
  428. Instruction.__init__(self)
  429. self.key_value_pairs = key_value_pairs
  430. def has_definition(self):
  431. """Tells if this instruction requires a definition."""
  432. return any(
  433. [key.has_definition() or val.has_definition()
  434. for key, val in self.key_value_pairs])
  435. def simplify(self):
  436. """Applies basic simplification to this instruction and its children."""
  437. return DictionaryLiteralInstruction(
  438. [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
  439. def generate_python_def(self, code_generator):
  440. """Generates a Python statement that executes this instruction.
  441. The statement is appended immediately to the code generator."""
  442. for key, val in self.key_value_pairs:
  443. if key.has_definition():
  444. key.generate_python_def(code_generator)
  445. if val.has_definition():
  446. val.generate_python_def(code_generator)
  447. def generate_python_use(self, code_generator):
  448. """Generates a Python expression that retrieves this instruction's
  449. result. The expression is returned as a string."""
  450. return '{ %s }' % ', '.join(
  451. ['%s : %s' % (
  452. key.generate_python_use(code_generator),
  453. val.generate_python_use(code_generator))
  454. for key, val in self.key_value_pairs])
  455. class StateInstruction(Instruction):
  456. """An instruction that accesses the modelverse state."""
  457. def get_opcode(self):
  458. """Gets the opcode for this state instruction."""
  459. raise NotImplementedError()
  460. def get_arguments(self):
  461. """Gets this state instruction's argument list."""
  462. raise NotImplementedError()
  463. def generate_python_def(self, code_generator):
  464. """Generates a Python statement that executes this instruction.
  465. The statement is appended immediately to the code generator."""
  466. args = self.get_arguments()
  467. for arg_i in args:
  468. if arg_i.has_definition():
  469. arg_i.generate_python_def(code_generator)
  470. code_generator.append_state_definition(self, self.get_opcode(), args)
  471. class VariableName(object):
  472. """A data structure that unifies names across instructions that access the
  473. same variable."""
  474. def __init__(self, name):
  475. self.name = name
  476. def get_result_name_override(self, _):
  477. """Gets a value that overrides the code generator's result name for this
  478. instruction if it is not None."""
  479. return self.name
  480. class VariableInstruction(Instruction):
  481. """A base class for instructions that access variables."""
  482. def __init__(self, name):
  483. Instruction.__init__(self)
  484. if isinstance(name, str) or isinstance(name, unicode) or name is None:
  485. self.name = VariableName(name)
  486. else:
  487. self.name = name
  488. def get_result_name_override(self, code_generator):
  489. """Gets a value that overrides the code generator's result name for this
  490. instruction if it is not None."""
  491. return code_generator.get_result_name(self.name)
  492. class LocalInstruction(VariableInstruction):
  493. """A base class for instructions that access local variables."""
  494. def create_load(self):
  495. """Creates an instruction that loads the variable referenced by this instruction."""
  496. return LoadLocalInstruction(self.name)
  497. def create_store(self, value):
  498. """Creates an instruction that stores the given value in the variable referenced
  499. by this instruction."""
  500. return StoreLocalInstruction(self.name, value)
  501. class StoreLocalInstruction(LocalInstruction):
  502. """An instruction that stores a value in a local variable."""
  503. def __init__(self, name, value):
  504. LocalInstruction.__init__(self, name)
  505. self.value = value
  506. def simplify(self):
  507. """Applies basic simplification to this instruction and its children."""
  508. return StoreLocalInstruction(self.name, self.value.simplify())
  509. def generate_python_def(self, code_generator):
  510. """Generates a Python statement that executes this instruction.
  511. The statement is appended immediately to the code generator."""
  512. code_generator.append_move_definition(self, self.value)
  513. class LoadLocalInstruction(LocalInstruction):
  514. """An instruction that loads a value from a local variable."""
  515. def has_definition(self):
  516. """Tells if this instruction requires a definition."""
  517. return False
  518. class DefineFunctionInstruction(VariableInstruction):
  519. """An instruction that defines a function."""
  520. def __init__(self, name, parameter_list, body):
  521. VariableInstruction.__init__(self, name)
  522. self.parameter_list = parameter_list
  523. self.body = body
  524. def generate_python_def(self, code_generator):
  525. """Generates a Python statement that executes this instruction.
  526. The statement is appended immediately to the code generator."""
  527. code_generator.append_line('def %s(%s):' % (
  528. code_generator.get_result_name(self), ', '.join(self.parameter_list)))
  529. code_generator.increase_indentation()
  530. self.body.generate_python_def(code_generator)
  531. code_generator.decrease_indentation()
  532. class LocalExistsInstruction(LocalInstruction):
  533. """An instruction that checks if a local variable exists."""
  534. def has_definition(self):
  535. """Tells if this instruction requires a definition."""
  536. return False
  537. def generate_python_use(self, code_generator):
  538. """Generates a Python expression that retrieves this instruction's
  539. result. The expression is returned as a string."""
  540. return "'%s' in locals()" % self.get_result_name_override(code_generator)
  541. class LoadGlobalInstruction(VariableInstruction):
  542. """An instruction that loads a value from a global variable."""
  543. def has_definition(self):
  544. """Tells if this instruction requires a definition."""
  545. return False
  546. class LoadIndexInstruction(Instruction):
  547. """An instruction that produces a value by indexing a specified expression with
  548. a given key."""
  549. def __init__(self, indexed, key):
  550. Instruction.__init__(self)
  551. self.indexed = indexed
  552. self.key = key
  553. def has_definition(self):
  554. """Tells if this instruction requires a definition."""
  555. return False
  556. def simplify(self):
  557. return LoadIndexInstruction(
  558. self.indexed.simplify(), self.key.simplify())
  559. def generate_python_use(self, code_generator):
  560. """Generates a Python expression that retrieves this instruction's
  561. result. The expression is returned as a string."""
  562. if self.indexed.has_definition():
  563. self.indexed.generate_python_def(code_generator)
  564. if self.key.has_definition():
  565. self.key.generate_python_def(code_generator)
  566. return "%s[%s]" % (
  567. self.indexed.generate_python_use(code_generator),
  568. self.key.generate_python_use(code_generator))
  569. class LoadMemberInstruction(Instruction):
  570. """An instruction that produces a value by loading a member from a container."""
  571. def __init__(self, container, member_name):
  572. Instruction.__init__(self)
  573. self.container = container
  574. self.member_name = member_name
  575. def has_definition(self):
  576. """Tells if this instruction requires a definition."""
  577. return self.container.has_definition()
  578. def simplify(self):
  579. return LoadMemberInstruction(
  580. self.container.simplify(), self.member_name)
  581. def generate_python_def(self, code_generator):
  582. """Generates a Python statement that executes this instruction.
  583. The statement is appended immediately to the code generator."""
  584. self.container.generate_python_def(code_generator)
  585. def generate_python_use(self, code_generator):
  586. """Generates a Python expression that retrieves this instruction's
  587. result. The expression is returned as a string."""
  588. return "%s.%s" % (
  589. self.container.generate_python_use(code_generator),
  590. self.member_name)
  591. class StoreMemberInstruction(Instruction):
  592. """An instruction that stores a value in a container member."""
  593. def __init__(self, container, member_name, value):
  594. Instruction.__init__(self)
  595. self.container = container
  596. self.member_name = member_name
  597. self.value = value
  598. def has_definition(self):
  599. """Tells if this instruction requires a definition."""
  600. return True
  601. def has_result(self):
  602. """Tells if this instruction computes a result."""
  603. return False
  604. def simplify(self):
  605. """Applies basic simplification to this instruction and its children."""
  606. return StoreMemberInstruction(
  607. self.container.simplify(), self.member_name, self.value.simplify())
  608. def generate_python_def(self, code_generator):
  609. """Generates a Python statement that executes this instruction.
  610. The statement is appended immediately to the code generator."""
  611. if self.container.has_definition():
  612. self.container.generate_python_def(code_generator)
  613. code_generator.append_line('%s.%s = %s' % (
  614. self.container.generate_python_use(code_generator),
  615. self.member_name,
  616. self.value.generate_python_use(code_generator)))
  617. class NopInstruction(Instruction):
  618. """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
  619. def has_result(self):
  620. """Tells if this instruction computes a result."""
  621. return False
  622. def generate_python_def(self, code_generator):
  623. """Generates a Python statement that executes this instruction.
  624. The statement is appended immediately to the code generator."""
  625. code_generator.append_line('yield %s' % repr(NOP_LITERAL))
  626. class ReadValueInstruction(StateInstruction):
  627. """An instruction that reads a value from a node."""
  628. def __init__(self, node_id):
  629. StateInstruction.__init__(self)
  630. self.node_id = node_id
  631. def simplify(self):
  632. """Applies basic simplification to this instruction and its children."""
  633. simplified_node_id = self.node_id.simplify()
  634. if isinstance(simplified_node_id, CreateNodeWithValueInstruction):
  635. return simplified_node_id.value
  636. else:
  637. return ReadValueInstruction(simplified_node_id)
  638. def get_opcode(self):
  639. """Gets the opcode for this state instruction."""
  640. return "RV"
  641. def get_arguments(self):
  642. """Gets this state instruction's argument list."""
  643. return [self.node_id]
  644. class ReadDictionaryValueInstruction(StateInstruction):
  645. """An instruction that reads a dictionary value."""
  646. def __init__(self, node_id, key):
  647. StateInstruction.__init__(self)
  648. self.node_id = node_id
  649. self.key = key
  650. def simplify(self):
  651. """Applies basic simplification to this instruction and its children."""
  652. return ReadDictionaryValueInstruction(
  653. self.node_id.simplify(),
  654. self.key.simplify())
  655. def get_opcode(self):
  656. """Gets the opcode for this state instruction."""
  657. return "RD"
  658. def get_arguments(self):
  659. """Gets this state instruction's argument list."""
  660. return [self.node_id, self.key]
  661. class ReadDictionaryEdgeInstruction(StateInstruction):
  662. """An instruction that reads a dictionary edge."""
  663. def __init__(self, node_id, key):
  664. StateInstruction.__init__(self)
  665. self.node_id = node_id
  666. self.key = key
  667. def simplify(self):
  668. """Applies basic simplification to this instruction and its children."""
  669. return ReadDictionaryEdgeInstruction(
  670. self.node_id.simplify(),
  671. self.key.simplify())
  672. def get_opcode(self):
  673. """Gets the opcode for this state instruction."""
  674. return "RDE"
  675. def get_arguments(self):
  676. """Gets this state instruction's argument list."""
  677. return [self.node_id, self.key]
  678. class ReadEdgeInstruction(StateInstruction):
  679. """An instruction that reads an edge."""
  680. def __init__(self, node_id):
  681. StateInstruction.__init__(self)
  682. self.node_id = node_id
  683. def simplify(self):
  684. """Applies basic simplification to this instruction and its children."""
  685. return ReadEdgeInstruction(
  686. self.node_id.simplify())
  687. def get_opcode(self):
  688. """Gets the opcode for this state instruction."""
  689. return "RE"
  690. def get_arguments(self):
  691. """Gets this state instruction's argument list."""
  692. return [self.node_id]
  693. class CreateNodeInstruction(StateInstruction):
  694. """An instruction that creates an empty node."""
  695. def get_opcode(self):
  696. """Gets the opcode for this state instruction."""
  697. return "CN"
  698. def get_arguments(self):
  699. """Gets this state instruction's argument list."""
  700. return []
  701. class CreateNodeWithValueInstruction(StateInstruction):
  702. """An instruction that creates a node with a given value."""
  703. def __init__(self, value):
  704. StateInstruction.__init__(self)
  705. self.value = value
  706. def simplify(self):
  707. """Applies basic simplification to this instruction and its children."""
  708. return CreateNodeWithValueInstruction(self.value.simplify())
  709. def get_opcode(self):
  710. """Gets the opcode for this state instruction."""
  711. return "CNV"
  712. def get_arguments(self):
  713. """Gets this state instruction's argument list."""
  714. return [self.value]
  715. class CreateEdgeInstruction(StateInstruction):
  716. """An instruction that creates an edge."""
  717. def __init__(self, source_id, target_id):
  718. StateInstruction.__init__(self)
  719. self.source_id = source_id
  720. self.target_id = target_id
  721. def simplify(self):
  722. """Applies basic simplification to this instruction and its children."""
  723. return CreateEdgeInstruction(
  724. self.source_id.simplify(),
  725. self.target_id.simplify())
  726. def get_opcode(self):
  727. """Gets the opcode for this state instruction."""
  728. return "CE"
  729. def get_arguments(self):
  730. """Gets this state instruction's argument list."""
  731. return [self.source_id, self.target_id]
  732. class CreateDictionaryEdgeInstruction(StateInstruction):
  733. """An instruction that creates a dictionary edge."""
  734. def __init__(self, source_id, key, target_id):
  735. StateInstruction.__init__(self)
  736. self.source_id = source_id
  737. self.key = key
  738. self.target_id = target_id
  739. def simplify(self):
  740. """Applies basic simplification to this instruction and its children."""
  741. return CreateDictionaryEdgeInstruction(
  742. self.source_id.simplify(),
  743. self.key.simplify(),
  744. self.target_id.simplify())
  745. def get_opcode(self):
  746. """Gets the opcode for this state instruction."""
  747. return "CD"
  748. def get_arguments(self):
  749. """Gets this state instruction's argument list."""
  750. return [self.source_id, self.key, self.target_id]
  751. class DeleteNodeInstruction(StateInstruction):
  752. """An instruction that deletes a node."""
  753. def __init__(self, node_id):
  754. StateInstruction.__init__(self)
  755. self.node_id = node_id
  756. def simplify(self):
  757. """Applies basic simplification to this instruction and its children."""
  758. return DeleteNodeInstruction(self.node_id.simplify())
  759. def has_result(self):
  760. """Tells if this instruction computes a result."""
  761. return False
  762. def get_opcode(self):
  763. """Gets the opcode for this state instruction."""
  764. return "DN"
  765. def get_arguments(self):
  766. """Gets this state instruction's argument list."""
  767. return [self.node_id]
  768. class DeleteEdgeInstruction(StateInstruction):
  769. """An instruction that deletes an edge."""
  770. def __init__(self, edge_id):
  771. StateInstruction.__init__(self)
  772. self.edge_id = edge_id
  773. def simplify(self):
  774. """Applies basic simplification to this instruction and its children."""
  775. return DeleteEdgeInstruction(self.edge_id.simplify())
  776. def has_result(self):
  777. """Tells if this instruction computes a result."""
  778. return False
  779. def get_opcode(self):
  780. """Gets the opcode for this state instruction."""
  781. return "DE"
  782. def get_arguments(self):
  783. """Gets this state instruction's argument list."""
  784. return [self.edge_id]
  785. def create_block(*statements):
  786. """Creates a block-statement from the given list of statements."""
  787. length = len(statements)
  788. if length == 0:
  789. return EmptyInstruction()
  790. elif length == 1:
  791. return statements[0]
  792. else:
  793. return CompoundInstruction(
  794. statements[0],
  795. create_block(*statements[1:]))
  796. def with_debug_info_trace(instruction, debug_info):
  797. """Prepends the given instruction with a tracing instruction that prints
  798. the given debug information."""
  799. if debug_info is None:
  800. return instruction
  801. else:
  802. return create_block(
  803. PrintInstruction(
  804. LiteralInstruction('TRACE: %s(JIT)' % debug_info)),
  805. instruction)
  806. if __name__ == "__main__":
  807. example_tree = SelectInstruction(
  808. LiteralInstruction(True),
  809. LoopInstruction(
  810. CompoundInstruction(
  811. BreakInstruction(),
  812. CompoundInstruction(
  813. EmptyInstruction(),
  814. ContinueInstruction()
  815. )
  816. )
  817. ),
  818. ReturnInstruction(
  819. EmptyInstruction()))
  820. print(example_tree.simplify())