/Lib/compiler/pycodegen.py

http://unladen-swallow.googlecode.com/ · Python · 1507 lines · 1216 code · 215 blank · 76 comment · 187 complexity · fec7d22abf03e8c31f510399b67e0ff9 MD5 · raw file

  1. import imp
  2. import os
  3. import marshal
  4. import struct
  5. import sys
  6. from cStringIO import StringIO
  7. from compiler import ast, parse, walk, syntax
  8. from compiler import pyassem, misc, future, symbols
  9. from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
  10. from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
  11. CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
  12. CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION)
  13. from compiler.pyassem import TupleArg
  14. callfunc_opcode_info = {
  15. # (Have *args, Have **args) : opcode
  16. (0,0) : "CALL_FUNCTION",
  17. (1,0) : "CALL_FUNCTION_VAR",
  18. (0,1) : "CALL_FUNCTION_KW",
  19. (1,1) : "CALL_FUNCTION_VAR_KW",
  20. }
  21. LOOP = 1
  22. EXCEPT = 2
  23. TRY_FINALLY = 3
  24. END_FINALLY = 4
  25. def compileFile(filename, display=0):
  26. f = open(filename, 'U')
  27. buf = f.read()
  28. f.close()
  29. mod = Module(buf, filename)
  30. try:
  31. mod.compile(display)
  32. except SyntaxError:
  33. raise
  34. else:
  35. f = open(filename + "c", "wb")
  36. mod.dump(f)
  37. f.close()
  38. def compile(source, filename, mode, flags=None, dont_inherit=None):
  39. """Replacement for builtin compile() function"""
  40. if flags is not None or dont_inherit is not None:
  41. raise RuntimeError, "not implemented yet"
  42. if mode == "single":
  43. gen = Interactive(source, filename)
  44. elif mode == "exec":
  45. gen = Module(source, filename)
  46. elif mode == "eval":
  47. gen = Expression(source, filename)
  48. else:
  49. raise ValueError("compile() 3rd arg must be 'exec' or "
  50. "'eval' or 'single'")
  51. gen.compile()
  52. return gen.code
  53. class AbstractCompileMode:
  54. mode = None # defined by subclass
  55. def __init__(self, source, filename):
  56. self.source = source
  57. self.filename = filename
  58. self.code = None
  59. def _get_tree(self):
  60. tree = parse(self.source, self.mode)
  61. misc.set_filename(self.filename, tree)
  62. syntax.check(tree)
  63. return tree
  64. def compile(self):
  65. pass # implemented by subclass
  66. def getCode(self):
  67. return self.code
  68. class Expression(AbstractCompileMode):
  69. mode = "eval"
  70. def compile(self):
  71. tree = self._get_tree()
  72. gen = ExpressionCodeGenerator(tree)
  73. self.code = gen.getCode()
  74. class Interactive(AbstractCompileMode):
  75. mode = "single"
  76. def compile(self):
  77. tree = self._get_tree()
  78. gen = InteractiveCodeGenerator(tree)
  79. self.code = gen.getCode()
  80. class Module(AbstractCompileMode):
  81. mode = "exec"
  82. def compile(self, display=0):
  83. tree = self._get_tree()
  84. gen = ModuleCodeGenerator(tree)
  85. if display:
  86. import pprint
  87. print pprint.pprint(tree)
  88. self.code = gen.getCode()
  89. def dump(self, f):
  90. f.write(self.getPycHeader())
  91. marshal.dump(self.code, f)
  92. MAGIC = imp.get_magic()
  93. def getPycHeader(self):
  94. # compile.c uses marshal to write a long directly, with
  95. # calling the interface that would also generate a 1-byte code
  96. # to indicate the type of the value. simplest way to get the
  97. # same effect is to call marshal and then skip the code.
  98. mtime = os.path.getmtime(self.filename)
  99. mtime = struct.pack('<i', mtime)
  100. return self.MAGIC + mtime
  101. class LocalNameFinder:
  102. """Find local names in scope"""
  103. def __init__(self, names=()):
  104. self.names = misc.Set()
  105. self.globals = misc.Set()
  106. for name in names:
  107. self.names.add(name)
  108. # XXX list comprehensions and for loops
  109. def getLocals(self):
  110. for elt in self.globals.elements():
  111. if self.names.has_elt(elt):
  112. self.names.remove(elt)
  113. return self.names
  114. def visitDict(self, node):
  115. pass
  116. def visitGlobal(self, node):
  117. for name in node.names:
  118. self.globals.add(name)
  119. def visitFunction(self, node):
  120. self.names.add(node.name)
  121. def visitLambda(self, node):
  122. pass
  123. def visitImport(self, node):
  124. for name, alias in node.names:
  125. self.names.add(alias or name)
  126. def visitFrom(self, node):
  127. for name, alias in node.names:
  128. self.names.add(alias or name)
  129. def visitClass(self, node):
  130. self.names.add(node.name)
  131. def visitAssName(self, node):
  132. self.names.add(node.name)
  133. def is_constant_false(node):
  134. if isinstance(node, ast.Const):
  135. if not node.value:
  136. return 1
  137. return 0
  138. class CodeGenerator:
  139. """Defines basic code generator for Python bytecode
  140. This class is an abstract base class. Concrete subclasses must
  141. define an __init__() that defines self.graph and then calls the
  142. __init__() defined in this class.
  143. The concrete class must also define the class attributes
  144. NameFinder, FunctionGen, and ClassGen. These attributes can be
  145. defined in the initClass() method, which is a hook for
  146. initializing these methods after all the classes have been
  147. defined.
  148. """
  149. optimized = 0 # is namespace access optimized?
  150. __initialized = None
  151. class_name = None # provide default for instance variable
  152. def __init__(self):
  153. if self.__initialized is None:
  154. self.initClass()
  155. self.__class__.__initialized = 1
  156. self.checkClass()
  157. self.locals = misc.Stack()
  158. self.setups = misc.Stack()
  159. self.last_lineno = None
  160. self._setupGraphDelegation()
  161. self._div_op = "BINARY_DIVIDE"
  162. # XXX set flags based on future features
  163. futures = self.get_module().futures
  164. for feature in futures:
  165. if feature == "division":
  166. self.graph.setFlag(CO_FUTURE_DIVISION)
  167. self._div_op = "BINARY_TRUE_DIVIDE"
  168. elif feature == "absolute_import":
  169. self.graph.setFlag(CO_FUTURE_ABSIMPORT)
  170. elif feature == "with_statement":
  171. self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)
  172. elif feature == "print_function":
  173. self.graph.setFlag(CO_FUTURE_PRINT_FUNCTION)
  174. def initClass(self):
  175. """This method is called once for each class"""
  176. def checkClass(self):
  177. """Verify that class is constructed correctly"""
  178. try:
  179. assert hasattr(self, 'graph')
  180. assert getattr(self, 'NameFinder')
  181. assert getattr(self, 'FunctionGen')
  182. assert getattr(self, 'ClassGen')
  183. except AssertionError, msg:
  184. intro = "Bad class construction for %s" % self.__class__.__name__
  185. raise AssertionError, intro
  186. def _setupGraphDelegation(self):
  187. self.emit = self.graph.emit
  188. self.newBlock = self.graph.newBlock
  189. self.startBlock = self.graph.startBlock
  190. self.nextBlock = self.graph.nextBlock
  191. self.setDocstring = self.graph.setDocstring
  192. def getCode(self):
  193. """Return a code object"""
  194. return self.graph.getCode()
  195. def mangle(self, name):
  196. if self.class_name is not None:
  197. return misc.mangle(name, self.class_name)
  198. else:
  199. return name
  200. def parseSymbols(self, tree):
  201. s = symbols.SymbolVisitor()
  202. walk(tree, s)
  203. return s.scopes
  204. def get_module(self):
  205. raise RuntimeError, "should be implemented by subclasses"
  206. # Next five methods handle name access
  207. def isLocalName(self, name):
  208. return self.locals.top().has_elt(name)
  209. def storeName(self, name):
  210. self._nameOp('STORE', name)
  211. def loadName(self, name):
  212. self._nameOp('LOAD', name)
  213. def delName(self, name):
  214. self._nameOp('DELETE', name)
  215. def _nameOp(self, prefix, name):
  216. name = self.mangle(name)
  217. scope = self.scope.check_name(name)
  218. if scope == SC_LOCAL:
  219. if not self.optimized:
  220. self.emit(prefix + '_NAME', name)
  221. else:
  222. self.emit(prefix + '_FAST', name)
  223. elif scope == SC_GLOBAL:
  224. if not self.optimized:
  225. self.emit(prefix + '_NAME', name)
  226. else:
  227. self.emit(prefix + '_GLOBAL', name)
  228. elif scope == SC_FREE or scope == SC_CELL:
  229. self.emit(prefix + '_DEREF', name)
  230. else:
  231. raise RuntimeError, "unsupported scope for var %s: %d" % \
  232. (name, scope)
  233. def _implicitNameOp(self, prefix, name):
  234. """Emit name ops for names generated implicitly by for loops
  235. The interpreter generates names that start with a period or
  236. dollar sign. The symbol table ignores these names because
  237. they aren't present in the program text.
  238. """
  239. if self.optimized:
  240. self.emit(prefix + '_FAST', name)
  241. else:
  242. self.emit(prefix + '_NAME', name)
  243. # The set_lineno() function and the explicit emit() calls for
  244. # SET_LINENO below are only used to generate the line number table.
  245. # As of Python 2.3, the interpreter does not have a SET_LINENO
  246. # instruction. pyassem treats SET_LINENO opcodes as a special case.
  247. def set_lineno(self, node, force=False):
  248. """Emit SET_LINENO if necessary.
  249. The instruction is considered necessary if the node has a
  250. lineno attribute and it is different than the last lineno
  251. emitted.
  252. Returns true if SET_LINENO was emitted.
  253. There are no rules for when an AST node should have a lineno
  254. attribute. The transformer and AST code need to be reviewed
  255. and a consistent policy implemented and documented. Until
  256. then, this method works around missing line numbers.
  257. """
  258. lineno = getattr(node, 'lineno', None)
  259. if lineno is not None and (lineno != self.last_lineno
  260. or force):
  261. self.emit('SET_LINENO', lineno)
  262. self.last_lineno = lineno
  263. return True
  264. return False
  265. # The first few visitor methods handle nodes that generator new
  266. # code objects. They use class attributes to determine what
  267. # specialized code generators to use.
  268. NameFinder = LocalNameFinder
  269. FunctionGen = None
  270. ClassGen = None
  271. def visitModule(self, node):
  272. self.scopes = self.parseSymbols(node)
  273. self.scope = self.scopes[node]
  274. self.emit('SET_LINENO', 0)
  275. if node.doc:
  276. self.emit('LOAD_CONST', node.doc)
  277. self.storeName('__doc__')
  278. lnf = walk(node.node, self.NameFinder(), verbose=0)
  279. self.locals.push(lnf.getLocals())
  280. self.visit(node.node)
  281. self.emit('LOAD_CONST', None)
  282. self.emit('RETURN_VALUE')
  283. def visitExpression(self, node):
  284. self.set_lineno(node)
  285. self.scopes = self.parseSymbols(node)
  286. self.scope = self.scopes[node]
  287. self.visit(node.node)
  288. self.emit('RETURN_VALUE')
  289. def visitFunction(self, node):
  290. self._visitFuncOrLambda(node, isLambda=0)
  291. if node.doc:
  292. self.setDocstring(node.doc)
  293. self.storeName(node.name)
  294. def visitLambda(self, node):
  295. self._visitFuncOrLambda(node, isLambda=1)
  296. def _visitFuncOrLambda(self, node, isLambda=0):
  297. if not isLambda and node.decorators:
  298. for decorator in node.decorators.nodes:
  299. self.visit(decorator)
  300. ndecorators = len(node.decorators.nodes)
  301. else:
  302. ndecorators = 0
  303. gen = self.FunctionGen(node, self.scopes, isLambda,
  304. self.class_name, self.get_module())
  305. walk(node.code, gen)
  306. gen.finish()
  307. self.set_lineno(node)
  308. self._makeClosure(gen, node.defaults)
  309. for i in range(ndecorators):
  310. self.emit('CALL_FUNCTION', 1)
  311. def visitClass(self, node):
  312. gen = self.ClassGen(node, self.scopes,
  313. self.get_module())
  314. walk(node.code, gen)
  315. gen.finish()
  316. self.set_lineno(node)
  317. self.emit('LOAD_GLOBAL', '#@buildclass')
  318. self.emit('LOAD_CONST', node.name)
  319. for base in node.bases:
  320. self.visit(base)
  321. self.emit('BUILD_TUPLE', len(node.bases))
  322. self._makeClosure(gen, [])
  323. self.emit('CALL_FUNCTION', 0) # Call the closure, get the locals dict
  324. self.emit('CALL_FUNCTION', 3) # Call #@buildclass
  325. self.storeName(node.name)
  326. # The rest are standard visitor methods
  327. # The next few implement control-flow statements
  328. def visitIf(self, node):
  329. end = self.newBlock()
  330. numtests = len(node.tests)
  331. for i in range(numtests):
  332. test, suite = node.tests[i]
  333. if is_constant_false(test):
  334. # XXX will need to check generator stuff here
  335. continue
  336. self.set_lineno(test)
  337. self.visit(test)
  338. nextTest = self.newBlock()
  339. self.emit('POP_JUMP_IF_FALSE', nextTest)
  340. self.nextBlock()
  341. self.visit(suite)
  342. self.emit('JUMP_FORWARD', end)
  343. self.startBlock(nextTest)
  344. if node.else_:
  345. self.visit(node.else_)
  346. self.nextBlock(end)
  347. def visitWhile(self, node):
  348. self.set_lineno(node)
  349. loop = self.newBlock()
  350. else_ = self.newBlock()
  351. after = self.newBlock()
  352. self.emit('SETUP_LOOP', after)
  353. self.nextBlock(loop)
  354. self.setups.push((LOOP, loop))
  355. self.set_lineno(node, force=True)
  356. self.visit(node.test)
  357. self.emit('POP_JUMP_IF_FALSE', else_ or after)
  358. self.nextBlock()
  359. self.visit(node.body)
  360. self.emit('JUMP_ABSOLUTE', loop)
  361. self.startBlock(else_) # or just the POPs if not else clause
  362. self.emit('POP_BLOCK')
  363. self.setups.pop()
  364. if node.else_:
  365. self.visit(node.else_)
  366. self.nextBlock(after)
  367. def visitFor(self, node):
  368. start = self.newBlock()
  369. anchor = self.newBlock()
  370. after = self.newBlock()
  371. self.setups.push((LOOP, start))
  372. self.set_lineno(node)
  373. self.emit('SETUP_LOOP', after)
  374. self.visit(node.list)
  375. self.emit('GET_ITER')
  376. self.nextBlock(start)
  377. self.set_lineno(node, force=1)
  378. self.emit('FOR_ITER', anchor)
  379. self.visit(node.assign)
  380. self.visit(node.body)
  381. self.emit('JUMP_ABSOLUTE', start)
  382. self.nextBlock(anchor)
  383. self.emit('POP_BLOCK')
  384. self.setups.pop()
  385. if node.else_:
  386. self.visit(node.else_)
  387. self.nextBlock(after)
  388. def visitBreak(self, node):
  389. if not self.setups:
  390. raise SyntaxError, "'break' outside loop (%s, %d)" % \
  391. (node.filename, node.lineno)
  392. self.set_lineno(node)
  393. self.emit('BREAK_LOOP')
  394. def visitContinue(self, node):
  395. if not self.setups:
  396. raise SyntaxError, "'continue' outside loop (%s, %d)" % \
  397. (node.filename, node.lineno)
  398. kind, block = self.setups.top()
  399. if kind == LOOP:
  400. self.set_lineno(node)
  401. self.emit('JUMP_ABSOLUTE', block)
  402. self.nextBlock()
  403. elif kind == EXCEPT or kind == TRY_FINALLY:
  404. self.set_lineno(node)
  405. # find the block that starts the loop
  406. top = len(self.setups)
  407. while top > 0:
  408. top = top - 1
  409. kind, loop_block = self.setups[top]
  410. if kind == LOOP:
  411. break
  412. if kind != LOOP:
  413. raise SyntaxError, "'continue' outside loop (%s, %d)" % \
  414. (node.filename, node.lineno)
  415. self.emit('CONTINUE_LOOP', loop_block)
  416. self.nextBlock()
  417. elif kind == END_FINALLY:
  418. msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
  419. raise SyntaxError, msg % (node.filename, node.lineno)
  420. def visitTest(self, node, jump):
  421. end = self.newBlock()
  422. for child in node.nodes[:-1]:
  423. self.visit(child)
  424. self.emit(jump, end)
  425. self.nextBlock()
  426. self.visit(node.nodes[-1])
  427. self.nextBlock(end)
  428. def visitAnd(self, node):
  429. self.visitTest(node, 'JUMP_IF_FALSE_OR_POP')
  430. def visitOr(self, node):
  431. self.visitTest(node, 'JUMP_IF_TRUE_OR_POP')
  432. def visitIfExp(self, node):
  433. endblock = self.newBlock()
  434. elseblock = self.newBlock()
  435. self.visit(node.test)
  436. self.emit('POP_JUMP_IF_FALSE', elseblock)
  437. self.visit(node.then)
  438. self.emit('JUMP_FORWARD', endblock)
  439. self.nextBlock(elseblock)
  440. self.visit(node.else_)
  441. self.nextBlock(endblock)
  442. def visitCompare(self, node):
  443. self.visit(node.expr)
  444. cleanup = self.newBlock()
  445. for op, code in node.ops[:-1]:
  446. self.visit(code)
  447. self.emit('DUP_TOP')
  448. self.emit('ROT_THREE')
  449. self.emit('COMPARE_OP', op)
  450. self.emit('JUMP_IF_FALSE_OR_POP', cleanup)
  451. self.nextBlock()
  452. # now do the last comparison
  453. if node.ops:
  454. op, code = node.ops[-1]
  455. self.visit(code)
  456. self.emit('COMPARE_OP', op)
  457. if len(node.ops) > 1:
  458. end = self.newBlock()
  459. self.emit('JUMP_FORWARD', end)
  460. self.startBlock(cleanup)
  461. self.emit('ROT_TWO')
  462. self.emit('POP_TOP')
  463. self.nextBlock(end)
  464. # list comprehensions
  465. __list_count = 0
  466. def visitListComp(self, node):
  467. self.set_lineno(node)
  468. # setup list
  469. tmpname = "$list%d" % self.__list_count
  470. self.__list_count = self.__list_count + 1
  471. self.emit('BUILD_LIST', 0)
  472. self.emit('DUP_TOP')
  473. self._implicitNameOp('STORE', tmpname)
  474. stack = []
  475. for i, for_ in zip(range(len(node.quals)), node.quals):
  476. start, anchor = self.visit(for_)
  477. cont = None
  478. for if_ in for_.ifs:
  479. if cont is None:
  480. cont = self.newBlock()
  481. self.visit(if_, cont)
  482. stack.insert(0, (start, cont, anchor))
  483. self._implicitNameOp('LOAD', tmpname)
  484. self.visit(node.expr)
  485. self.emit('LIST_APPEND')
  486. for start, cont, anchor in stack:
  487. if cont:
  488. self.nextBlock(cont)
  489. self.emit('JUMP_ABSOLUTE', start)
  490. self.startBlock(anchor)
  491. self._implicitNameOp('DELETE', tmpname)
  492. self.__list_count = self.__list_count - 1
  493. def visitListCompFor(self, node):
  494. start = self.newBlock()
  495. anchor = self.newBlock()
  496. self.visit(node.list)
  497. self.emit('GET_ITER')
  498. self.nextBlock(start)
  499. self.set_lineno(node, force=True)
  500. self.emit('FOR_ITER', anchor)
  501. self.nextBlock()
  502. self.visit(node.assign)
  503. return start, anchor
  504. def visitListCompIf(self, node, branch):
  505. self.set_lineno(node, force=True)
  506. self.visit(node.test)
  507. self.emit('POP_JUMP_IF_FALSE', branch)
  508. self.newBlock()
  509. def _makeClosure(self, gen, defaults):
  510. frees = gen.scope.get_free_vars()
  511. if frees:
  512. for default in defaults:
  513. self.visit(default)
  514. for name in frees:
  515. self.emit('LOAD_CLOSURE', name)
  516. self.emit('BUILD_TUPLE', len(frees))
  517. self.emit('LOAD_CONST', gen)
  518. self.emit('MAKE_CLOSURE', len(defaults))
  519. else:
  520. self.emit('LOAD_GLOBAL', '#@make_function')
  521. self.emit('LOAD_CONST', gen)
  522. for default in defaults:
  523. self.visit(default)
  524. self.emit('CALL_FUNCTION', len(defaults) + 1)
  525. def visitGenExpr(self, node):
  526. gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
  527. self.get_module())
  528. walk(node.code, gen)
  529. gen.finish()
  530. self.set_lineno(node)
  531. self._makeClosure(gen, [])
  532. # precomputation of outmost iterable
  533. self.visit(node.code.quals[0].iter)
  534. self.emit('GET_ITER')
  535. self.emit('CALL_FUNCTION', 1)
  536. def visitGenExprInner(self, node):
  537. self.set_lineno(node)
  538. # setup list
  539. stack = []
  540. for i, for_ in zip(range(len(node.quals)), node.quals):
  541. start, anchor, end = self.visit(for_)
  542. cont = None
  543. for if_ in for_.ifs:
  544. if cont is None:
  545. cont = self.newBlock()
  546. self.visit(if_, cont)
  547. stack.insert(0, (start, cont, anchor, end))
  548. self.visit(node.expr)
  549. self.emit('YIELD_VALUE')
  550. self.emit('POP_TOP')
  551. for start, cont, anchor, end in stack:
  552. if cont:
  553. self.nextBlock(cont)
  554. self.emit('JUMP_ABSOLUTE', start)
  555. self.startBlock(anchor)
  556. self.emit('POP_BLOCK')
  557. self.setups.pop()
  558. self.nextBlock(end)
  559. self.emit('LOAD_CONST', None)
  560. def visitGenExprFor(self, node):
  561. start = self.newBlock()
  562. anchor = self.newBlock()
  563. end = self.newBlock()
  564. self.setups.push((LOOP, start))
  565. self.emit('SETUP_LOOP', end)
  566. if node.is_outmost:
  567. self.loadName('.0')
  568. else:
  569. self.visit(node.iter)
  570. self.emit('GET_ITER')
  571. self.nextBlock(start)
  572. self.set_lineno(node, force=True)
  573. self.emit('FOR_ITER', anchor)
  574. self.nextBlock()
  575. self.visit(node.assign)
  576. return start, anchor, end
  577. def visitGenExprIf(self, node, branch):
  578. self.set_lineno(node, force=True)
  579. self.visit(node.test)
  580. self.emit('POP_JUMP_IF_FALSE', branch)
  581. self.newBlock()
  582. # exception related
  583. def visitAssert(self, node):
  584. # XXX would be interesting to implement this via a
  585. # transformation of the AST before this stage
  586. if __debug__:
  587. end = self.newBlock()
  588. self.set_lineno(node)
  589. # XXX AssertionError appears to be special case -- it is always
  590. # loaded as a global even if there is a local name. I guess this
  591. # is a sort of renaming op.
  592. self.nextBlock()
  593. self.visit(node.test)
  594. self.emit('POP_JUMP_IF_TRUE', end)
  595. self.nextBlock()
  596. self.emit('LOAD_GLOBAL', 'AssertionError')
  597. if node.fail:
  598. self.visit(node.fail)
  599. self.emit('RAISE_VARARGS_TWO')
  600. else:
  601. self.emit('RAISE_VARARGS_ONE')
  602. self.nextBlock(end)
  603. def visitRaise(self, node):
  604. self.set_lineno(node)
  605. n = 0
  606. if node.expr1:
  607. self.visit(node.expr1)
  608. n = n + 1
  609. if node.expr2:
  610. self.visit(node.expr2)
  611. n = n + 1
  612. if node.expr3:
  613. self.visit(node.expr3)
  614. n = n + 1
  615. self.emit('RAISE_VARARGS_' + ('ZERO', 'ONE', 'TWO', 'THREE')[n])
  616. def visitTryExcept(self, node):
  617. body = self.newBlock()
  618. handlers = self.newBlock()
  619. end = self.newBlock()
  620. if node.else_:
  621. lElse = self.newBlock()
  622. else:
  623. lElse = end
  624. self.set_lineno(node)
  625. self.emit('SETUP_EXCEPT', handlers)
  626. self.nextBlock(body)
  627. self.setups.push((EXCEPT, body))
  628. self.visit(node.body)
  629. self.emit('POP_BLOCK')
  630. self.setups.pop()
  631. self.emit('JUMP_FORWARD', lElse)
  632. self.startBlock(handlers)
  633. last = len(node.handlers) - 1
  634. for i in range(len(node.handlers)):
  635. expr, target, body = node.handlers[i]
  636. self.set_lineno(expr)
  637. if expr:
  638. self.emit('DUP_TOP')
  639. self.visit(expr)
  640. self.emit('COMPARE_OP', 'exception match')
  641. next = self.newBlock()
  642. self.emit('POP_JUMP_IF_FALSE', next)
  643. self.nextBlock()
  644. self.emit('POP_TOP')
  645. if target:
  646. self.visit(target)
  647. else:
  648. self.emit('POP_TOP')
  649. self.emit('POP_TOP')
  650. self.visit(body)
  651. self.emit('JUMP_FORWARD', end)
  652. if expr:
  653. self.nextBlock(next)
  654. else:
  655. self.nextBlock()
  656. self.emit('END_FINALLY')
  657. if node.else_:
  658. self.nextBlock(lElse)
  659. self.visit(node.else_)
  660. self.nextBlock(end)
  661. def visitTryFinally(self, node):
  662. body = self.newBlock()
  663. final = self.newBlock()
  664. self.set_lineno(node)
  665. self.emit('SETUP_FINALLY', final)
  666. self.nextBlock(body)
  667. self.setups.push((TRY_FINALLY, body))
  668. self.visit(node.body)
  669. self.emit('POP_BLOCK')
  670. self.setups.pop()
  671. self.emit('LOAD_CONST', None)
  672. self.emit('DUP_TOP')
  673. self.emit('DUP_TOP')
  674. self.nextBlock(final)
  675. self.setups.push((END_FINALLY, final))
  676. self.visit(node.final)
  677. self.emit('END_FINALLY')
  678. self.setups.pop()
  679. __with_count = 0
  680. def visitWith(self, node):
  681. body = self.newBlock()
  682. final = self.newBlock()
  683. valuevar = "$value%d" % self.__with_count
  684. self.__with_count += 1
  685. self.set_lineno(node)
  686. self.visit(node.expr)
  687. self.emit('DUP_TOP')
  688. self.emit('LOAD_ATTR', '__exit__')
  689. self.emit('ROT_TWO')
  690. self.emit('LOAD_ATTR', '__enter__')
  691. self.emit('CALL_FUNCTION', 0)
  692. if node.vars is None:
  693. self.emit('POP_TOP')
  694. else:
  695. self._implicitNameOp('STORE', valuevar)
  696. self.emit('SETUP_FINALLY', final)
  697. self.nextBlock(body)
  698. self.setups.push((TRY_FINALLY, body))
  699. if node.vars is not None:
  700. self._implicitNameOp('LOAD', valuevar)
  701. self._implicitNameOp('DELETE', valuevar)
  702. self.visit(node.vars)
  703. self.visit(node.body)
  704. self.emit('POP_BLOCK')
  705. self.setups.pop()
  706. self.emit('LOAD_CONST', None)
  707. self.emit('DUP_TOP')
  708. self.emit('DUP_TOP')
  709. self.nextBlock(final)
  710. self.setups.push((END_FINALLY, final))
  711. self.emit('WITH_CLEANUP')
  712. self.emit('END_FINALLY')
  713. self.setups.pop()
  714. self.__with_count -= 1
  715. # misc
  716. def visitDiscard(self, node):
  717. self.set_lineno(node)
  718. self.visit(node.expr)
  719. self.emit('POP_TOP')
  720. def visitConst(self, node):
  721. self.emit('LOAD_CONST', node.value)
  722. def visitKeyword(self, node):
  723. self.emit('LOAD_CONST', node.name)
  724. self.visit(node.expr)
  725. def visitGlobal(self, node):
  726. # no code to generate
  727. pass
  728. def visitName(self, node):
  729. self.set_lineno(node)
  730. self.loadName(node.name)
  731. def visitPass(self, node):
  732. self.set_lineno(node)
  733. def visitImport(self, node):
  734. self.set_lineno(node)
  735. level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1
  736. for name, alias in node.names:
  737. self.emit('LOAD_CONST', level)
  738. self.emit('LOAD_CONST', None)
  739. self.emit('LOAD_CONST', name)
  740. self.emit('IMPORT_NAME')
  741. mod = name.split(".")[0]
  742. if alias:
  743. self._resolveDots(name)
  744. self.storeName(alias)
  745. else:
  746. self.storeName(mod)
  747. def visitFrom(self, node):
  748. self.set_lineno(node)
  749. level = node.level
  750. if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
  751. level = -1
  752. fromlist = map(lambda (name, alias): name, node.names)
  753. # Handle 'from x import *' statements.
  754. if node.names[0][0] == '*':
  755. # There can only be one name w/ from ... import *
  756. assert len(node.names) == 1
  757. self.namespace = 0
  758. self.emit('LOAD_GLOBAL', '#@import_star')
  759. self.emit('LOAD_CONST', level)
  760. self.emit('LOAD_CONST', tuple(fromlist))
  761. self.emit('LOAD_CONST', node.modname)
  762. self.emit('IMPORT_NAME')
  763. self.emit('CALL_FUNCTION', 1)
  764. self.emit('POP_TOP')
  765. return
  766. self.emit('LOAD_GLOBAL', '#@import_from')
  767. self.emit('LOAD_CONST', level)
  768. self.emit('LOAD_CONST', tuple(fromlist))
  769. self.emit('LOAD_CONST', node.modname)
  770. self.emit('IMPORT_NAME')
  771. for name, alias in node.names:
  772. # The DUP_TOP_TWO is duplicating [#@import_from, module], where
  773. # module is the return value from IMPORT_NAME.
  774. self.emit('DUP_TOP_TWO')
  775. self.emit('LOAD_CONST', name)
  776. self.emit('CALL_FUNCTION', 2)
  777. self._resolveDots(name)
  778. self.storeName(alias or name)
  779. self.emit('POP_TOP') # Remove the imported module.
  780. self.emit('POP_TOP') # Remove the #@import_from function.
  781. def _resolveDots(self, name):
  782. elts = name.split(".")
  783. if len(elts) == 1:
  784. return
  785. for elt in elts[1:]:
  786. self.emit('LOAD_ATTR', elt)
  787. def visitGetattr(self, node):
  788. self.visit(node.expr)
  789. self.emit('LOAD_ATTR', self.mangle(node.attrname))
  790. # next five implement assignments
  791. def visitAssign(self, node):
  792. self.set_lineno(node)
  793. self.visit(node.expr)
  794. dups = len(node.nodes) - 1
  795. for i in range(len(node.nodes)):
  796. elt = node.nodes[i]
  797. if i < dups:
  798. self.emit('DUP_TOP')
  799. if isinstance(elt, ast.Node):
  800. self.visit(elt)
  801. def visitAssName(self, node):
  802. if node.flags == 'OP_ASSIGN':
  803. self.storeName(node.name)
  804. elif node.flags == 'OP_DELETE':
  805. self.set_lineno(node)
  806. self.delName(node.name)
  807. else:
  808. print "oops", node.flags
  809. def visitAssAttr(self, node):
  810. self.visit(node.expr)
  811. if node.flags == 'OP_ASSIGN':
  812. self.emit('STORE_ATTR', self.mangle(node.attrname))
  813. elif node.flags == 'OP_DELETE':
  814. self.emit('DELETE_ATTR', self.mangle(node.attrname))
  815. else:
  816. print "warning: unexpected flags:", node.flags
  817. print node
  818. def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
  819. if findOp(node) != 'OP_DELETE':
  820. self.emit(op, len(node.nodes))
  821. for child in node.nodes:
  822. self.visit(child)
  823. visitAssTuple = _visitAssSequence
  824. visitAssList = _visitAssSequence
  825. # augmented assignment
  826. def visitAugAssign(self, node):
  827. self.set_lineno(node)
  828. aug_node = wrap_aug(node.node)
  829. self.visit(aug_node, "load")
  830. self.visit(node.expr)
  831. self.emit(self._augmented_opcode[node.op])
  832. self.visit(aug_node, "store")
  833. _augmented_opcode = {
  834. '+=' : 'INPLACE_ADD',
  835. '-=' : 'INPLACE_SUBTRACT',
  836. '*=' : 'INPLACE_MULTIPLY',
  837. '/=' : 'INPLACE_DIVIDE',
  838. '//=': 'INPLACE_FLOOR_DIVIDE',
  839. '%=' : 'INPLACE_MODULO',
  840. '**=': 'INPLACE_POWER',
  841. '>>=': 'INPLACE_RSHIFT',
  842. '<<=': 'INPLACE_LSHIFT',
  843. '&=' : 'INPLACE_AND',
  844. '^=' : 'INPLACE_XOR',
  845. '|=' : 'INPLACE_OR',
  846. }
  847. def visitAugName(self, node, mode):
  848. if mode == "load":
  849. self.loadName(node.name)
  850. elif mode == "store":
  851. self.storeName(node.name)
  852. def visitAugGetattr(self, node, mode):
  853. if mode == "load":
  854. self.visit(node.expr)
  855. self.emit('DUP_TOP')
  856. self.emit('LOAD_ATTR', self.mangle(node.attrname))
  857. elif mode == "store":
  858. self.emit('ROT_TWO')
  859. self.emit('STORE_ATTR', self.mangle(node.attrname))
  860. def visitAugSlice(self, node, mode):
  861. if mode == "load":
  862. self.visitSlice(node, 1)
  863. elif mode == "store":
  864. slice = 0
  865. if node.lower:
  866. slice = slice | 1
  867. if node.upper:
  868. slice = slice | 2
  869. if slice == 0:
  870. self.emit('ROT_TWO')
  871. elif slice == 3:
  872. self.emit('ROT_FOUR')
  873. else:
  874. self.emit('ROT_THREE')
  875. self.emit('STORE_SLICE_' + ('NONE', 'LEFT', 'RIGHT', 'BOTH')[slice])
  876. def visitAugSubscript(self, node, mode):
  877. if mode == "load":
  878. self.visitSubscript(node, 1)
  879. elif mode == "store":
  880. self.emit('ROT_THREE')
  881. self.emit('STORE_SUBSCR')
  882. def visitExec(self, node):
  883. self.emit('LOAD_GLOBAL', '#@exec')
  884. self.visit(node.expr)
  885. if node.locals is None:
  886. self.emit('LOAD_CONST', None)
  887. else:
  888. self.visit(node.locals)
  889. if node.globals is None:
  890. self.emit('DUP_TOP')
  891. else:
  892. self.visit(node.globals)
  893. self.emit('CALL_FUNCTION', 3)
  894. self.emit('POP_TOP')
  895. def visitCallFunc(self, node):
  896. pos = 0
  897. kw = 0
  898. self.set_lineno(node)
  899. self.visit(node.node)
  900. for arg in node.args:
  901. self.visit(arg)
  902. if isinstance(arg, ast.Keyword):
  903. kw = kw + 1
  904. else:
  905. pos = pos + 1
  906. if node.star_args is not None:
  907. self.visit(node.star_args)
  908. if node.dstar_args is not None:
  909. self.visit(node.dstar_args)
  910. have_star = node.star_args is not None
  911. have_dstar = node.dstar_args is not None
  912. opcode = callfunc_opcode_info[have_star, have_dstar]
  913. self.emit(opcode, kw << 8 | pos)
  914. def visitPrint(self, node):
  915. kwargs = 0
  916. self.set_lineno(node)
  917. self.emit('LOAD_GLOBAL', '#@print_stmt')
  918. for child in node.nodes:
  919. self.visit(child)
  920. if not node.newline:
  921. self.emit('LOAD_CONST', 'end')
  922. self.emit('LOAD_CONST', '')
  923. kwargs += 1
  924. if node.dest:
  925. self.emit('LOAD_CONST', 'file')
  926. self.visit(node.dest)
  927. kwargs += 1
  928. self.emit('CALL_FUNCTION', len(node.nodes) | (kwargs << 8))
  929. self.emit('POP_TOP')
  930. def visitReturn(self, node):
  931. self.set_lineno(node)
  932. self.visit(node.value)
  933. self.emit('RETURN_VALUE')
  934. def visitYield(self, node):
  935. self.set_lineno(node)
  936. self.visit(node.value)
  937. self.emit('YIELD_VALUE')
  938. # slice and subscript stuff
  939. def visitSlice(self, node, aug_flag=None):
  940. # aug_flag is used by visitAugSlice
  941. self.visit(node.expr)
  942. slice = 0
  943. if node.lower:
  944. self.visit(node.lower)
  945. slice = slice | 1
  946. if node.upper:
  947. self.visit(node.upper)
  948. slice = slice | 2
  949. if aug_flag:
  950. if slice == 0:
  951. self.emit('DUP_TOP')
  952. elif slice == 3:
  953. self.emit('DUP_TOP_THREE')
  954. else:
  955. self.emit('DUP_TOP_TWO')
  956. if node.flags == 'OP_APPLY':
  957. self.emit('SLICE_' + ('NONE', 'LEFT', 'RIGHT', 'BOTH')[slice])
  958. elif node.flags == 'OP_ASSIGN':
  959. self.emit('STORE_SLICE_' + ('NONE', 'LEFT', 'RIGHT', 'BOTH')[slice])
  960. elif node.flags == 'OP_DELETE':
  961. self.emit('DELETE_SLICE_' + ('NONE', 'LEFT', 'RIGHT', 'BOTH')[slice])
  962. else:
  963. print "weird slice", node.flags
  964. raise
  965. def visitSubscript(self, node, aug_flag=None):
  966. self.visit(node.expr)
  967. for sub in node.subs:
  968. self.visit(sub)
  969. if len(node.subs) > 1:
  970. self.emit('BUILD_TUPLE', len(node.subs))
  971. if aug_flag:
  972. self.emit('DUP_TOP_TWO')
  973. if node.flags == 'OP_APPLY':
  974. self.emit('BINARY_SUBSCR')
  975. elif node.flags == 'OP_ASSIGN':
  976. self.emit('STORE_SUBSCR')
  977. elif node.flags == 'OP_DELETE':
  978. self.emit('DELETE_SUBSCR')
  979. # binary ops
  980. def binaryOp(self, node, op):
  981. self.visit(node.left)
  982. self.visit(node.right)
  983. self.emit(op)
  984. def visitAdd(self, node):
  985. return self.binaryOp(node, 'BINARY_ADD')
  986. def visitSub(self, node):
  987. return self.binaryOp(node, 'BINARY_SUBTRACT')
  988. def visitMul(self, node):
  989. return self.binaryOp(node, 'BINARY_MULTIPLY')
  990. def visitDiv(self, node):
  991. return self.binaryOp(node, self._div_op)
  992. def visitFloorDiv(self, node):
  993. return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
  994. def visitMod(self, node):
  995. return self.binaryOp(node, 'BINARY_MODULO')
  996. def visitPower(self, node):
  997. return self.binaryOp(node, 'BINARY_POWER')
  998. def visitLeftShift(self, node):
  999. return self.binaryOp(node, 'BINARY_LSHIFT')
  1000. def visitRightShift(self, node):
  1001. return self.binaryOp(node, 'BINARY_RSHIFT')
  1002. # unary ops
  1003. def unaryOp(self, node, op):
  1004. self.visit(node.expr)
  1005. self.emit(op)
  1006. def visitInvert(self, node):
  1007. return self.unaryOp(node, 'UNARY_INVERT')
  1008. def visitUnarySub(self, node):
  1009. return self.unaryOp(node, 'UNARY_NEGATIVE')
  1010. def visitUnaryAdd(self, node):
  1011. return self.unaryOp(node, 'UNARY_POSITIVE')
  1012. def visitUnaryInvert(self, node):
  1013. return self.unaryOp(node, 'UNARY_INVERT')
  1014. def visitNot(self, node):
  1015. return self.unaryOp(node, 'UNARY_NOT')
  1016. def visitBackquote(self, node):
  1017. return self.unaryOp(node, 'UNARY_CONVERT')
  1018. # bit ops
  1019. def bitOp(self, nodes, op):
  1020. self.visit(nodes[0])
  1021. for node in nodes[1:]:
  1022. self.visit(node)
  1023. self.emit(op)
  1024. def visitBitand(self, node):
  1025. return self.bitOp(node.nodes, 'BINARY_AND')
  1026. def visitBitor(self, node):
  1027. return self.bitOp(node.nodes, 'BINARY_OR')
  1028. def visitBitxor(self, node):
  1029. return self.bitOp(node.nodes, 'BINARY_XOR')
  1030. # object constructors
  1031. def visitEllipsis(self, node):
  1032. self.emit('LOAD_CONST', Ellipsis)
  1033. def visitTuple(self, node):
  1034. self.set_lineno(node)
  1035. for elt in node.nodes:
  1036. self.visit(elt)
  1037. self.emit('BUILD_TUPLE', len(node.nodes))
  1038. def visitList(self, node):
  1039. self.set_lineno(node)
  1040. for elt in node.nodes:
  1041. self.visit(elt)
  1042. self.emit('BUILD_LIST', len(node.nodes))
  1043. def visitSliceobj(self, node):
  1044. for child in node.nodes:
  1045. self.visit(child)
  1046. # ZERO and ONE aren't actually used.
  1047. self.emit('BUILD_SLICE_' + ('ZERO', 'ONE', 'TWO', 'THREE')[len(node.nodes)])
  1048. def visitDict(self, node):
  1049. self.set_lineno(node)
  1050. self.emit('BUILD_MAP', 0)
  1051. for k, v in node.items:
  1052. self.emit('DUP_TOP')
  1053. self.visit(k)
  1054. self.visit(v)
  1055. self.emit('ROT_THREE')
  1056. self.emit('STORE_SUBSCR')
  1057. class NestedScopeMixin:
  1058. """Defines initClass() for nested scoping (Python 2.2-compatible)"""
  1059. def initClass(self):
  1060. self.__class__.NameFinder = LocalNameFinder
  1061. self.__class__.FunctionGen = FunctionCodeGenerator
  1062. self.__class__.ClassGen = ClassCodeGenerator
  1063. class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
  1064. __super_init = CodeGenerator.__init__
  1065. scopes = None
  1066. def __init__(self, tree):
  1067. self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
  1068. self.futures = future.find_futures(tree)
  1069. self.__super_init()
  1070. walk(tree, self)
  1071. def get_module(self):
  1072. return self
  1073. class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
  1074. __super_init = CodeGenerator.__init__
  1075. scopes = None
  1076. futures = ()
  1077. def __init__(self, tree):
  1078. self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
  1079. self.__super_init()
  1080. walk(tree, self)
  1081. def get_module(self):
  1082. return self
  1083. class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
  1084. __super_init = CodeGenerator.__init__
  1085. scopes = None
  1086. futures = ()
  1087. def __init__(self, tree):
  1088. self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
  1089. self.__super_init()
  1090. self.set_lineno(tree)
  1091. walk(tree, self)
  1092. self.emit('RETURN_VALUE')
  1093. def get_module(self):
  1094. return self
  1095. def visitDiscard(self, node):
  1096. # XXX Discard means it's an expression. Perhaps this is a bad
  1097. # name.
  1098. self.emit('LOAD_GLOBAL', '#@displayhook')
  1099. self.visit(node.expr)
  1100. self.emit('CALL_FUNCTION', 1)
  1101. self.emit('POP_TOP')
  1102. class AbstractFunctionCode:
  1103. optimized = 1
  1104. lambdaCount = 0
  1105. def __init__(self, func, scopes, isLambda, class_name, mod):
  1106. self.class_name = class_name
  1107. self.module = mod
  1108. if isLambda:
  1109. klass = FunctionCodeGenerator
  1110. name = "<lambda.%d>" % klass.lambdaCount
  1111. klass.lambdaCount = klass.lambdaCount + 1
  1112. else:
  1113. name = func.name
  1114. args, hasTupleArg = generateArgList(func.argnames)
  1115. self.graph = pyassem.PyFlowGraph(name, func.filename, args,
  1116. optimized=1)
  1117. self.isLambda = isLambda
  1118. self.super_init()
  1119. if not isLambda and func.doc:
  1120. self.setDocstring(func.doc)
  1121. lnf = walk(func.code, self.NameFinder(args), verbose=0)
  1122. self.locals.push(lnf.getLocals())
  1123. if func.varargs:
  1124. self.graph.setFlag(CO_VARARGS)
  1125. if func.kwargs:
  1126. self.graph.setFlag(CO_VARKEYWORDS)
  1127. self.set_lineno(func)
  1128. if hasTupleArg:
  1129. self.generateArgUnpack(func.argnames)
  1130. def get_module(self):
  1131. return self.module
  1132. def finish(self):
  1133. self.graph.startExitBlock()
  1134. if not self.isLambda:
  1135. self.emit('LOAD_CONST', None)
  1136. self.emit('RETURN_VALUE')
  1137. def generateArgUnpack(self, args):
  1138. for i in range(len(args)):
  1139. arg = args[i]
  1140. if isinstance(arg, tuple):
  1141. self.emit('LOAD_FAST', '.%d' % (i * 2))
  1142. self.unpackSequence(arg)
  1143. def unpackSequence(self, tup):
  1144. self.emit('UNPACK_SEQUENCE', len(tup))
  1145. for elt in tup:
  1146. if isinstance(elt, tuple):
  1147. self.unpackSequence(elt)
  1148. else:
  1149. self._nameOp('STORE', elt)
  1150. unpackTuple = unpackSequence
  1151. class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
  1152. CodeGenerator):
  1153. super_init = CodeGenerator.__init__ # call be other init
  1154. scopes = None
  1155. __super_init = AbstractFunctionCode.__init__
  1156. def __init__(self, func, scopes, isLambda, class_name, mod):
  1157. self.scopes = scopes
  1158. self.scope = scopes[func]
  1159. self.__super_init(func, scopes, isLambda, class_name, mod)
  1160. self.graph.setFreeVars(self.scope.get_free_vars())
  1161. self.graph.setCellVars(self.scope.get_cell_vars())
  1162. if self.scope.generator is not None:
  1163. self.graph.setFlag(CO_GENERATOR)
  1164. class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
  1165. CodeGenerator):
  1166. super_init = CodeGenerator.__init__ # call be other init
  1167. scopes = None
  1168. __super_init = AbstractFunctionCode.__init__
  1169. def __init__(self, gexp, scopes, class_name, mod):
  1170. self.scopes = scopes
  1171. self.scope = scopes[gexp]
  1172. self.__super_init(gexp, scopes, 1, class_name, mod)
  1173. self.graph.setFreeVars(self.scope.get_free_vars())
  1174. self.graph.setCellVars(self.scope.get_cell_vars())
  1175. self.graph.setFlag(CO_GENERATOR)
  1176. class AbstractClassCode:
  1177. def __init__(self, klass, scopes, module):
  1178. self.class_name = klass.name
  1179. self.module = module
  1180. self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
  1181. optimized=0, klass=1)
  1182. self.super_init()
  1183. lnf = walk(klass.code, self.NameFinder(), verbose=0)
  1184. self.locals.push(lnf.getLocals())
  1185. self.graph.setFlag(CO_NEWLOCALS)
  1186. if klass.doc:
  1187. self.setDocstring(klass.doc)
  1188. def get_module(self):
  1189. return self.module
  1190. def finish(self):
  1191. self.graph.startExitBlock()
  1192. self.emit('LOAD_GLOBAL', '#@locals')
  1193. self.emit('CALL_FUNCTION', 0)
  1194. self.emit('RETURN_VALUE')
  1195. class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
  1196. super_init = CodeGenerator.__init__
  1197. scopes = None
  1198. __super_init = AbstractClassCode.__init__
  1199. def __init__(self, klass, scopes, module):
  1200. self.scopes = scopes
  1201. self.scope = scopes[klass]
  1202. self.__super_init(klass, scopes, module)
  1203. self.graph.setFreeVars(self.scope.get_free_vars())
  1204. self.graph.setCellVars(self.scope.get_cell_vars())
  1205. self.set_lineno(klass)
  1206. self.emit("LOAD_GLOBAL", "__name__")
  1207. self.storeName("__module__")
  1208. if klass.doc:
  1209. self.emit("LOAD_CONST", klass.doc)
  1210. self.storeName('__doc__')
  1211. def generateArgList(arglist):
  1212. """Generate an arg list marking TupleArgs"""
  1213. args = []
  1214. extra = []
  1215. count = 0
  1216. for i in range(len(arglist)):
  1217. elt = arglist[i]
  1218. if isinstance(elt, str):
  1219. args.append(elt)
  1220. elif isinstance(elt, tuple):
  1221. args.append(TupleArg(i * 2, elt))
  1222. extra.extend(misc.flatten(elt))
  1223. count = count + 1
  1224. else:
  1225. raise ValueError, "unexpect argument type:", elt
  1226. return args + extra, count
  1227. def findOp(node):
  1228. """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
  1229. v = OpFinder()
  1230. walk(node, v, verbose=0)
  1231. return v.op
  1232. class OpFinder:
  1233. def __init__(self):
  1234. self.op = None
  1235. def visitAssName(self, node):
  1236. if self.op is None:
  1237. self.op = node.flags
  1238. elif self.op != node.flags:
  1239. raise ValueError, "mixed ops in stmt"
  1240. visitAssAttr = visitAssName
  1241. visitSubscript = visitAssName
  1242. class Delegator:
  1243. """Base class to support delegation for augmented assignment nodes
  1244. To generator code for augmented assignments, we use the following
  1245. wrapper classes. In visitAugAssign, the left-hand expression node
  1246. is visited twice. The first time the visit uses the normal method
  1247. for that node . The second time the visit uses a different method
  1248. that generates the appropriate code to perform the assignment.
  1249. These delegator classes wrap the original AST nodes in order to
  1250. support the variant visit methods.
  1251. """
  1252. def __init__(self, obj):
  1253. self.obj = obj
  1254. def __getattr__(self, attr):
  1255. return getattr(self.obj, attr)
  1256. class AugGetattr(Delegator):
  1257. pass
  1258. class AugName(Delegator):
  1259. pass
  1260. class AugSlice(Delegator):
  1261. pass
  1262. class AugSubscript(Delegator):
  1263. pass
  1264. wrapper = {
  1265. ast.Getattr: AugGetattr,
  1266. ast.Name: AugName,
  1267. ast.Slice: AugSlice,
  1268. ast.Subscript: AugSubscript,
  1269. }
  1270. def wrap_aug(node):
  1271. return wrapper[node.__class__](node)
  1272. if __name__ == "__main__":
  1273. for file in sys.argv[1:]:
  1274. compileFile(file)