tree_ir.py 44 KB

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