tree_ir.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  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. code_generator.append_line('try:')
  264. code_generator.increase_indentation()
  265. code_generator.append_line(
  266. 'gen = %s(%s) ' % (
  267. self.target.generate_python_use(code_generator),
  268. ', '.join(arg_list)))
  269. code_generator.append_line('inp = None')
  270. code_generator.append_line('while 1:')
  271. code_generator.increase_indentation()
  272. code_generator.append_line('inp = yield gen.send(inp)')
  273. code_generator.decrease_indentation()
  274. code_generator.decrease_indentation()
  275. code_generator.append_line('except PrimitiveFinished as ex:')
  276. code_generator.increase_indentation()
  277. code_generator.append_line('%s = ex.result' % code_generator.get_result_name(self))
  278. code_generator.decrease_indentation()
  279. class BinaryInstruction(Instruction):
  280. """An instruction that performs a binary operation."""
  281. def __init__(self, lhs, operator, rhs):
  282. Instruction.__init__(self)
  283. self.lhs = lhs
  284. self.operator = operator
  285. self.rhs = rhs
  286. def has_definition(self):
  287. """Tells if this instruction requires a definition."""
  288. return self.lhs.has_definition() or self.rhs.has_definition()
  289. def simplify(self):
  290. """Applies basic simplification to this instruction and its children."""
  291. simple_lhs, simple_rhs = self.lhs.simplify(), self.rhs.simplify()
  292. return BinaryInstruction(simple_lhs, self.operator, simple_rhs)
  293. def generate_python_use(self, code_generator):
  294. """Generates a Python expression that retrieves this instruction's
  295. result. The expression is returned as a string."""
  296. return '(%s %s %s)' % (
  297. self.lhs.generate_python_use(code_generator),
  298. self.operator,
  299. self.rhs.generate_python_use(code_generator))
  300. def generate_python_def(self, code_generator):
  301. """Generates a Python statement that executes this instruction.
  302. The statement is appended immediately to the code generator."""
  303. if self.lhs.has_definition():
  304. self.lhs.generate_python_def(code_generator)
  305. if self.rhs.has_definition():
  306. self.rhs.generate_python_def(code_generator)
  307. elif self.rhs.has_definition():
  308. self.rhs.generate_python_def(code_generator)
  309. else:
  310. code_generator.append_line('pass')
  311. class UnaryInstruction(Instruction):
  312. """An instruction that performs a unary operation."""
  313. def __init__(self, operator, operand):
  314. Instruction.__init__(self)
  315. self.operator = operator
  316. self.operand = operand
  317. def has_definition(self):
  318. """Tells if this instruction requires a definition."""
  319. return self.operand.has_definition()
  320. def simplify(self):
  321. """Applies basic simplification to this instruction and its children."""
  322. simple_operand = self.operand.simplify()
  323. return UnaryInstruction(self.operator, simple_operand)
  324. def generate_python_use(self, code_generator):
  325. """Generates a Python expression that retrieves this instruction's
  326. result. The expression is returned as a string."""
  327. return '(%s %s)' % (
  328. self.operator,
  329. self.operand.generate_python_use(code_generator))
  330. def generate_python_def(self, code_generator):
  331. """Generates a Python statement that executes this instruction.
  332. The statement is appended immediately to the code generator."""
  333. if self.operand.has_definition():
  334. self.operand.generate_python_def(code_generator)
  335. else:
  336. code_generator.append_line('pass')
  337. class LoopInstruction(VoidInstruction):
  338. """Represents a loop-instruction, which loops until broken."""
  339. def __init__(self, body):
  340. VoidInstruction.__init__(self)
  341. self.body = body
  342. def simplify(self):
  343. """Applies basic simplification to this instruction and its children."""
  344. return LoopInstruction(self.body.simplify())
  345. def generate_python_def(self, code_generator):
  346. """Generates Python code for this instruction."""
  347. code_generator.append_line('while 1:')
  348. code_generator.increase_indentation()
  349. self.body.generate_python_def(code_generator)
  350. code_generator.decrease_indentation()
  351. class BreakInstruction(VoidInstruction):
  352. """Represents a break-instruction."""
  353. def generate_python_def(self, code_generator):
  354. """Generates Python code for this instruction."""
  355. code_generator.append_line('break')
  356. class ContinueInstruction(VoidInstruction):
  357. """Represents a continue-instruction."""
  358. def generate_python_def(self, code_generator):
  359. """Generates Python code for this instruction."""
  360. code_generator.append_line('continue')
  361. class CompoundInstruction(Instruction):
  362. """Represents an instruction that evaluates two other instructions
  363. in order, and returns the second instruction's result."""
  364. def __init__(self, first, second):
  365. Instruction.__init__(self)
  366. self.first = first
  367. self.second = second
  368. def has_result(self):
  369. """Tells if this instruction has a result."""
  370. return self.second.has_result() or self.first.has_result()
  371. def simplify(self):
  372. """Applies basic simplification to this instruction and its children."""
  373. simple_fst, simple_snd = self.first.simplify(), self.second.simplify()
  374. if not simple_fst.has_definition() and (
  375. not simple_fst.has_result() or simple_snd.has_result()):
  376. return simple_snd
  377. elif (not simple_snd.has_definition()) and (not simple_snd.has_result()):
  378. return simple_fst
  379. else:
  380. return CompoundInstruction(simple_fst, simple_snd)
  381. def generate_python_def(self, code_generator):
  382. """Generates Python code for this instruction."""
  383. if self.second.has_result():
  384. self.first.generate_python_def(code_generator)
  385. code_generator.append_move_definition(self, self.second)
  386. elif self.first.has_result():
  387. code_generator.append_move_definition(self, self.first)
  388. self.second.generate_python_def(code_generator)
  389. else:
  390. self.first.generate_python_def(code_generator)
  391. self.second.generate_python_def(code_generator)
  392. class LiteralInstruction(Instruction):
  393. """Represents an integer, floating-point, string or Boolean literal."""
  394. def __init__(self, literal):
  395. Instruction.__init__(self)
  396. self.literal = literal
  397. def has_definition(self):
  398. """Tells if this instruction requires a definition."""
  399. return False
  400. def generate_python_use(self, code_generator):
  401. """Generates a Python expression that retrieves this instruction's
  402. result. The expression is returned as a string."""
  403. return repr(self.literal)
  404. class DictionaryLiteralInstruction(Instruction):
  405. """Constructs a dictionary literal."""
  406. def __init__(self, key_value_pairs):
  407. Instruction.__init__(self)
  408. self.key_value_pairs = key_value_pairs
  409. def has_definition(self):
  410. """Tells if this instruction requires a definition."""
  411. return any(
  412. [key.has_definition() or val.has_definition()
  413. for key, val in self.key_value_pairs])
  414. def simplify(self):
  415. """Applies basic simplification to this instruction and its children."""
  416. return DictionaryLiteralInstruction(
  417. [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
  418. def generate_python_def(self, code_generator):
  419. """Generates a Python statement that executes this instruction.
  420. The statement is appended immediately to the code generator."""
  421. for key, val in self.key_value_pairs:
  422. if key.has_definition():
  423. key.generate_python_def(code_generator)
  424. if val.has_definition():
  425. val.generate_python_def(code_generator)
  426. def generate_python_use(self, code_generator):
  427. """Generates a Python expression that retrieves this instruction's
  428. result. The expression is returned as a string."""
  429. return '{ %s }' % ', '.join(
  430. ['%s : %s' % (
  431. key.generate_python_use(code_generator),
  432. val.generate_python_use(code_generator))
  433. for key, val in self.key_value_pairs])
  434. class StateInstruction(Instruction):
  435. """An instruction that accesses the modelverse state."""
  436. def get_opcode(self):
  437. """Gets the opcode for this state instruction."""
  438. raise NotImplementedError()
  439. def get_arguments(self):
  440. """Gets this state instruction's argument list."""
  441. raise NotImplementedError()
  442. def generate_python_def(self, code_generator):
  443. """Generates a Python statement that executes this instruction.
  444. The statement is appended immediately to the code generator."""
  445. args = self.get_arguments()
  446. for arg_i in args:
  447. if arg_i.has_definition():
  448. arg_i.generate_python_def(code_generator)
  449. code_generator.append_state_definition(self, self.get_opcode(), args)
  450. class VariableName(object):
  451. """A data structure that unifies names across instructions that access the
  452. same variable."""
  453. def __init__(self, name):
  454. self.name = name
  455. def get_result_name_override(self, _):
  456. """Gets a value that overrides the code generator's result name for this
  457. instruction if it is not None."""
  458. return self.name
  459. class VariableInstruction(Instruction):
  460. """A base class for instructions that access variables."""
  461. def __init__(self, name):
  462. Instruction.__init__(self)
  463. if isinstance(name, str) or isinstance(name, unicode) or name is None:
  464. self.name = VariableName(name)
  465. else:
  466. self.name = name
  467. def get_result_name_override(self, code_generator):
  468. """Gets a value that overrides the code generator's result name for this
  469. instruction if it is not None."""
  470. return code_generator.get_result_name(self.name)
  471. class LocalInstruction(VariableInstruction):
  472. """A base class for instructions that access local variables."""
  473. def create_load(self):
  474. """Creates an instruction that loads the variable referenced by this instruction."""
  475. return LoadLocalInstruction(self.name)
  476. def create_store(self, value):
  477. """Creates an instruction that stores the given value in the variable referenced
  478. by this instruction."""
  479. return StoreLocalInstruction(self.name, value)
  480. class StoreLocalInstruction(LocalInstruction):
  481. """An instruction that stores a value in a local variable."""
  482. def __init__(self, name, value):
  483. LocalInstruction.__init__(self, name)
  484. self.value = value
  485. def simplify(self):
  486. """Applies basic simplification to this instruction and its children."""
  487. return StoreLocalInstruction(self.name, self.value.simplify())
  488. def generate_python_def(self, code_generator):
  489. """Generates a Python statement that executes this instruction.
  490. The statement is appended immediately to the code generator."""
  491. code_generator.append_move_definition(self, self.value)
  492. class LoadLocalInstruction(LocalInstruction):
  493. """An instruction that loads a value from a local variable."""
  494. def has_definition(self):
  495. """Tells if this instruction requires a definition."""
  496. return False
  497. class DefineFunctionInstruction(VariableInstruction):
  498. """An instruction that defines a function."""
  499. def __init__(self, name, parameter_list, body):
  500. VariableInstruction.__init__(self, name)
  501. self.parameter_list = parameter_list
  502. self.body = body
  503. def generate_python_def(self, code_generator):
  504. """Generates a Python statement that executes this instruction.
  505. The statement is appended immediately to the code generator."""
  506. code_generator.append_line('def %s(%s):' % (
  507. code_generator.get_result_name(self), ', '.join(self.parameter_list)))
  508. code_generator.increase_indentation()
  509. self.body.generate_python_def(code_generator)
  510. code_generator.decrease_indentation()
  511. class LocalExistsInstruction(LocalInstruction):
  512. """An instruction that checks if a local variable exists."""
  513. def has_definition(self):
  514. """Tells if this instruction requires a definition."""
  515. return False
  516. def generate_python_use(self, code_generator):
  517. """Generates a Python expression that retrieves this instruction's
  518. result. The expression is returned as a string."""
  519. return "'%s' in locals()" % self.get_result_name_override(code_generator)
  520. class LoadGlobalInstruction(VariableInstruction):
  521. """An instruction that loads a value from a global variable."""
  522. def has_definition(self):
  523. """Tells if this instruction requires a definition."""
  524. return False
  525. class LoadIndexInstruction(Instruction):
  526. """An instruction that produces a value by indexing a specified expression with
  527. a given key."""
  528. def __init__(self, indexed, key):
  529. Instruction.__init__(self)
  530. self.indexed = indexed
  531. self.key = key
  532. def has_definition(self):
  533. """Tells if this instruction requires a definition."""
  534. return False
  535. def simplify(self):
  536. return LoadIndexInstruction(
  537. self.indexed.simplify(), self.key.simplify())
  538. def generate_python_use(self, code_generator):
  539. """Generates a Python expression that retrieves this instruction's
  540. result. The expression is returned as a string."""
  541. if self.indexed.has_definition():
  542. self.indexed.generate_python_def(code_generator)
  543. if self.key.has_definition():
  544. self.key.generate_python_def(code_generator)
  545. return "%s[%s]" % (
  546. self.indexed.generate_python_use(code_generator),
  547. self.key.generate_python_use(code_generator))
  548. class LoadMemberInstruction(Instruction):
  549. """An instruction that produces a value by loading a member from a container."""
  550. def __init__(self, container, member_name):
  551. Instruction.__init__(self)
  552. self.container = container
  553. self.member_name = member_name
  554. def has_definition(self):
  555. """Tells if this instruction requires a definition."""
  556. return self.container.has_definition()
  557. def simplify(self):
  558. return LoadMemberInstruction(
  559. self.container.simplify(), self.member_name)
  560. def generate_python_def(self, code_generator):
  561. """Generates a Python statement that executes this instruction.
  562. The statement is appended immediately to the code generator."""
  563. self.container.generate_python_def(code_generator)
  564. def generate_python_use(self, code_generator):
  565. """Generates a Python expression that retrieves this instruction's
  566. result. The expression is returned as a string."""
  567. return "%s.%s" % (
  568. self.container.generate_python_use(code_generator),
  569. self.member_name)
  570. class StoreMemberInstruction(Instruction):
  571. """An instruction that stores a value in a container member."""
  572. def __init__(self, container, member_name, value):
  573. Instruction.__init__(self)
  574. self.container = container
  575. self.member_name = member_name
  576. self.value = value
  577. def has_definition(self):
  578. """Tells if this instruction requires a definition."""
  579. return True
  580. def has_result(self):
  581. """Tells if this instruction computes a result."""
  582. return False
  583. def simplify(self):
  584. """Applies basic simplification to this instruction and its children."""
  585. return StoreMemberInstruction(
  586. self.container.simplify(), self.member_name, self.value.simplify())
  587. def generate_python_def(self, code_generator):
  588. """Generates a Python statement that executes this instruction.
  589. The statement is appended immediately to the code generator."""
  590. if self.container.has_definition():
  591. self.container.generate_python_def(code_generator)
  592. code_generator.append_line('%s.%s = %s' % (
  593. self.container.generate_python_use(code_generator),
  594. self.member_name,
  595. self.value.generate_python_use(code_generator)))
  596. class NopInstruction(Instruction):
  597. """A nop instruction, which allows for the kernel's thread of execution to be interrupted."""
  598. def has_result(self):
  599. """Tells if this instruction computes a result."""
  600. return False
  601. def generate_python_def(self, code_generator):
  602. """Generates a Python statement that executes this instruction.
  603. The statement is appended immediately to the code generator."""
  604. code_generator.append_line('yield %s' % repr(NOP_LITERAL))
  605. class ReadValueInstruction(StateInstruction):
  606. """An instruction that reads a value from a node."""
  607. def __init__(self, node_id):
  608. StateInstruction.__init__(self)
  609. self.node_id = node_id
  610. def simplify(self):
  611. """Applies basic simplification to this instruction and its children."""
  612. simplified_node_id = self.node_id.simplify()
  613. if isinstance(simplified_node_id, CreateNodeWithValueInstruction):
  614. return simplified_node_id.value
  615. else:
  616. return ReadValueInstruction(simplified_node_id)
  617. def get_opcode(self):
  618. """Gets the opcode for this state instruction."""
  619. return "RV"
  620. def get_arguments(self):
  621. """Gets this state instruction's argument list."""
  622. return [self.node_id]
  623. class ReadDictionaryValueInstruction(StateInstruction):
  624. """An instruction that reads a dictionary value."""
  625. def __init__(self, node_id, key):
  626. StateInstruction.__init__(self)
  627. self.node_id = node_id
  628. self.key = key
  629. def simplify(self):
  630. """Applies basic simplification to this instruction and its children."""
  631. return ReadDictionaryValueInstruction(
  632. self.node_id.simplify(),
  633. self.key.simplify())
  634. def get_opcode(self):
  635. """Gets the opcode for this state instruction."""
  636. return "RD"
  637. def get_arguments(self):
  638. """Gets this state instruction's argument list."""
  639. return [self.node_id, self.key]
  640. class ReadDictionaryEdgeInstruction(StateInstruction):
  641. """An instruction that reads a dictionary edge."""
  642. def __init__(self, node_id, key):
  643. StateInstruction.__init__(self)
  644. self.node_id = node_id
  645. self.key = key
  646. def simplify(self):
  647. """Applies basic simplification to this instruction and its children."""
  648. return ReadDictionaryEdgeInstruction(
  649. self.node_id.simplify(),
  650. self.key.simplify())
  651. def get_opcode(self):
  652. """Gets the opcode for this state instruction."""
  653. return "RDE"
  654. def get_arguments(self):
  655. """Gets this state instruction's argument list."""
  656. return [self.node_id, self.key]
  657. class ReadEdgeInstruction(StateInstruction):
  658. """An instruction that reads an edge."""
  659. def __init__(self, node_id):
  660. StateInstruction.__init__(self)
  661. self.node_id = node_id
  662. def simplify(self):
  663. """Applies basic simplification to this instruction and its children."""
  664. return ReadEdgeInstruction(
  665. self.node_id.simplify())
  666. def get_opcode(self):
  667. """Gets the opcode for this state instruction."""
  668. return "RE"
  669. def get_arguments(self):
  670. """Gets this state instruction's argument list."""
  671. return [self.node_id]
  672. class CreateNodeInstruction(StateInstruction):
  673. """An instruction that creates an empty node."""
  674. def get_opcode(self):
  675. """Gets the opcode for this state instruction."""
  676. return "CN"
  677. def get_arguments(self):
  678. """Gets this state instruction's argument list."""
  679. return []
  680. class CreateNodeWithValueInstruction(StateInstruction):
  681. """An instruction that creates a node with a given value."""
  682. def __init__(self, value):
  683. StateInstruction.__init__(self)
  684. self.value = value
  685. def simplify(self):
  686. """Applies basic simplification to this instruction and its children."""
  687. return CreateNodeWithValueInstruction(self.value.simplify())
  688. def get_opcode(self):
  689. """Gets the opcode for this state instruction."""
  690. return "CNV"
  691. def get_arguments(self):
  692. """Gets this state instruction's argument list."""
  693. return [self.value]
  694. class CreateEdgeInstruction(StateInstruction):
  695. """An instruction that creates an edge."""
  696. def __init__(self, source_id, target_id):
  697. StateInstruction.__init__(self)
  698. self.source_id = source_id
  699. self.target_id = target_id
  700. def simplify(self):
  701. """Applies basic simplification to this instruction and its children."""
  702. return CreateEdgeInstruction(
  703. self.source_id.simplify(),
  704. self.target_id.simplify())
  705. def get_opcode(self):
  706. """Gets the opcode for this state instruction."""
  707. return "CE"
  708. def get_arguments(self):
  709. """Gets this state instruction's argument list."""
  710. return [self.source_id, self.target_id]
  711. class CreateDictionaryEdgeInstruction(StateInstruction):
  712. """An instruction that creates a dictionary edge."""
  713. def __init__(self, source_id, key, target_id):
  714. StateInstruction.__init__(self)
  715. self.source_id = source_id
  716. self.key = key
  717. self.target_id = target_id
  718. def simplify(self):
  719. """Applies basic simplification to this instruction and its children."""
  720. return CreateDictionaryEdgeInstruction(
  721. self.source_id.simplify(),
  722. self.key.simplify(),
  723. self.target_id.simplify())
  724. def get_opcode(self):
  725. """Gets the opcode for this state instruction."""
  726. return "CD"
  727. def get_arguments(self):
  728. """Gets this state instruction's argument list."""
  729. return [self.source_id, self.key, self.target_id]
  730. class DeleteNodeInstruction(StateInstruction):
  731. """An instruction that deletes a node."""
  732. def __init__(self, node_id):
  733. StateInstruction.__init__(self)
  734. self.node_id = node_id
  735. def simplify(self):
  736. """Applies basic simplification to this instruction and its children."""
  737. return DeleteNodeInstruction(self.node_id.simplify())
  738. def has_result(self):
  739. """Tells if this instruction computes a result."""
  740. return False
  741. def get_opcode(self):
  742. """Gets the opcode for this state instruction."""
  743. return "DN"
  744. def get_arguments(self):
  745. """Gets this state instruction's argument list."""
  746. return [self.node_id]
  747. class DeleteEdgeInstruction(StateInstruction):
  748. """An instruction that deletes an edge."""
  749. def __init__(self, edge_id):
  750. StateInstruction.__init__(self)
  751. self.edge_id = edge_id
  752. def simplify(self):
  753. """Applies basic simplification to this instruction and its children."""
  754. return DeleteEdgeInstruction(self.edge_id.simplify())
  755. def has_result(self):
  756. """Tells if this instruction computes a result."""
  757. return False
  758. def get_opcode(self):
  759. """Gets the opcode for this state instruction."""
  760. return "DE"
  761. def get_arguments(self):
  762. """Gets this state instruction's argument list."""
  763. return [self.edge_id]
  764. def create_block(*statements):
  765. """Creates a block-statement from the given list of statements."""
  766. length = len(statements)
  767. if length == 0:
  768. return EmptyInstruction()
  769. elif length == 1:
  770. return statements[0]
  771. else:
  772. return CompoundInstruction(
  773. statements[0],
  774. create_block(*statements[1:]))
  775. if __name__ == "__main__":
  776. example_tree = SelectInstruction(
  777. LiteralInstruction(True),
  778. LoopInstruction(
  779. CompoundInstruction(
  780. BreakInstruction(),
  781. CompoundInstruction(
  782. EmptyInstruction(),
  783. ContinueInstruction()
  784. )
  785. )
  786. ),
  787. ReturnInstruction(
  788. EmptyInstruction()))
  789. print(example_tree.simplify())