mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	Add support for absolute/relative imports and if/else expressions:
- regenerate ast.py - add future flags for absolute-import and with-statement so they (hopefully) properly get set in code-object flags - try out if/else expressions in actual code for the hell of it. Seems to generate the same kind of bytecode as the normal compiler.
This commit is contained in:
		
							parent
							
								
									7e2ac2533e
								
							
						
					
					
						commit
						fa0cf4f3ae
					
				
					 5 changed files with 82 additions and 19 deletions
				
			
		|  | @ -524,19 +524,20 @@ def __repr__(self): | ||||||
|         return "For(%s, %s, %s, %s)" % (repr(self.assign), repr(self.list), repr(self.body), repr(self.else_)) |         return "For(%s, %s, %s, %s)" % (repr(self.assign), repr(self.list), repr(self.body), repr(self.else_)) | ||||||
| 
 | 
 | ||||||
| class From(Node): | class From(Node): | ||||||
|     def __init__(self, modname, names, lineno=None): |     def __init__(self, modname, names, level, lineno=None): | ||||||
|         self.modname = modname |         self.modname = modname | ||||||
|         self.names = names |         self.names = names | ||||||
|  |         self.level = level | ||||||
|         self.lineno = lineno |         self.lineno = lineno | ||||||
| 
 | 
 | ||||||
|     def getChildren(self): |     def getChildren(self): | ||||||
|         return self.modname, self.names |         return self.modname, self.names, self.level | ||||||
| 
 | 
 | ||||||
|     def getChildNodes(self): |     def getChildNodes(self): | ||||||
|         return () |         return () | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "From(%s, %s)" % (repr(self.modname), repr(self.names)) |         return "From(%s, %s, %s)" % (repr(self.modname), repr(self.names), repr(self.level)) | ||||||
| 
 | 
 | ||||||
| class Function(Node): | class Function(Node): | ||||||
|     def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None): |     def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None): | ||||||
|  | @ -708,6 +709,22 @@ def getChildNodes(self): | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return "If(%s, %s)" % (repr(self.tests), repr(self.else_)) |         return "If(%s, %s)" % (repr(self.tests), repr(self.else_)) | ||||||
| 
 | 
 | ||||||
|  | class IfExp(Node): | ||||||
|  |     def __init__(self, test, then, else_, lineno=None): | ||||||
|  |         self.test = test | ||||||
|  |         self.then = then | ||||||
|  |         self.else_ = else_ | ||||||
|  |         self.lineno = lineno | ||||||
|  | 
 | ||||||
|  |     def getChildren(self): | ||||||
|  |         return self.test, self.then, self.else_ | ||||||
|  | 
 | ||||||
|  |     def getChildNodes(self): | ||||||
|  |         return self.test, self.then, self.else_ | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         return "IfExp(%s, %s, %s)" % (repr(self.test), repr(self.then), repr(self.else_)) | ||||||
|  | 
 | ||||||
| class Import(Node): | class Import(Node): | ||||||
|     def __init__(self, names, lineno=None): |     def __init__(self, names, lineno=None): | ||||||
|         self.names = names |         self.names = names | ||||||
|  |  | ||||||
|  | @ -17,3 +17,5 @@ | ||||||
| CO_GENERATOR = 0x0020 | CO_GENERATOR = 0x0020 | ||||||
| CO_GENERATOR_ALLOWED = 0x1000 | CO_GENERATOR_ALLOWED = 0x1000 | ||||||
| CO_FUTURE_DIVISION = 0x2000 | CO_FUTURE_DIVISION = 0x2000 | ||||||
|  | CO_FUTURE_ABSIMPORT = 0x4000 | ||||||
|  | CO_FUTURE_WITH_STATEMENT = 0x8000 | ||||||
|  |  | ||||||
|  | @ -771,7 +771,7 @@ def findDepth(self, insts, debug=0): | ||||||
|         'COMPARE_OP': -1, |         'COMPARE_OP': -1, | ||||||
|         'STORE_FAST': -1, |         'STORE_FAST': -1, | ||||||
|         'IMPORT_STAR': -1, |         'IMPORT_STAR': -1, | ||||||
|         'IMPORT_NAME': 0, |         'IMPORT_NAME': -1, | ||||||
|         'IMPORT_FROM': 1, |         'IMPORT_FROM': 1, | ||||||
|         'LOAD_ATTR': 0, # unlike other loads |         'LOAD_ATTR': 0, # unlike other loads | ||||||
|         # close enough... |         # close enough... | ||||||
|  |  | ||||||
|  | @ -8,8 +8,9 @@ | ||||||
| from compiler import ast, parse, walk, syntax | from compiler import ast, parse, walk, syntax | ||||||
| from compiler import pyassem, misc, future, symbols | from compiler import pyassem, misc, future, symbols | ||||||
| from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL | from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL | ||||||
| from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\ | from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, | ||||||
|      CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION |      CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION, | ||||||
|  |      CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT) | ||||||
| from compiler.pyassem import TupleArg | from compiler.pyassem import TupleArg | ||||||
| 
 | 
 | ||||||
| # XXX The version-specific code can go, since this code only works with 2.x. | # XXX The version-specific code can go, since this code only works with 2.x. | ||||||
|  | @ -215,6 +216,10 @@ def __init__(self): | ||||||
|                 self._div_op = "BINARY_TRUE_DIVIDE" |                 self._div_op = "BINARY_TRUE_DIVIDE" | ||||||
|             elif feature == "generators": |             elif feature == "generators": | ||||||
|                 self.graph.setFlag(CO_GENERATOR_ALLOWED) |                 self.graph.setFlag(CO_GENERATOR_ALLOWED) | ||||||
|  |             elif feature == "absolute_import": | ||||||
|  |                 self.graph.setFlag(CO_FUTURE_ABSIMPORT) | ||||||
|  |             elif feature == "with_statement": | ||||||
|  |                 self.graph.setFlag(CO_FUTURE_WITH_STATEMENT) | ||||||
| 
 | 
 | ||||||
|     def initClass(self): |     def initClass(self): | ||||||
|         """This method is called once for each class""" |         """This method is called once for each class""" | ||||||
|  | @ -543,6 +548,19 @@ def visitAnd(self, node): | ||||||
|     def visitOr(self, node): |     def visitOr(self, node): | ||||||
|         self.visitTest(node, 'JUMP_IF_TRUE') |         self.visitTest(node, 'JUMP_IF_TRUE') | ||||||
| 
 | 
 | ||||||
|  |     def visitIfExp(self, node): | ||||||
|  |         endblock = self.newBlock() | ||||||
|  |         elseblock = self.newBlock() | ||||||
|  |         self.visit(node.test) | ||||||
|  |         self.emit('JUMP_IF_FALSE', elseblock) | ||||||
|  |         self.emit('POP_TOP') | ||||||
|  |         self.visit(node.then) | ||||||
|  |         self.emit('JUMP_FORWARD', endblock) | ||||||
|  |         self.nextBlock(elseblock) | ||||||
|  |         self.emit('POP_TOP') | ||||||
|  |         self.visit(node.else_) | ||||||
|  |         self.nextBlock(endblock) | ||||||
|  | 
 | ||||||
|     def visitCompare(self, node): |     def visitCompare(self, node): | ||||||
|         self.visit(node.expr) |         self.visit(node.expr) | ||||||
|         cleanup = self.newBlock() |         cleanup = self.newBlock() | ||||||
|  | @ -875,8 +893,10 @@ def visitPass(self, node): | ||||||
| 
 | 
 | ||||||
|     def visitImport(self, node): |     def visitImport(self, node): | ||||||
|         self.set_lineno(node) |         self.set_lineno(node) | ||||||
|  |         level = 0 if "absolute_import" in self.futures else -1 | ||||||
|         for name, alias in node.names: |         for name, alias in node.names: | ||||||
|             if VERSION > 1: |             if VERSION > 1: | ||||||
|  |                 self.emit('LOAD_CONST', level) | ||||||
|                 self.emit('LOAD_CONST', None) |                 self.emit('LOAD_CONST', None) | ||||||
|             self.emit('IMPORT_NAME', name) |             self.emit('IMPORT_NAME', name) | ||||||
|             mod = name.split(".")[0] |             mod = name.split(".")[0] | ||||||
|  | @ -888,8 +908,12 @@ def visitImport(self, node): | ||||||
| 
 | 
 | ||||||
|     def visitFrom(self, node): |     def visitFrom(self, node): | ||||||
|         self.set_lineno(node) |         self.set_lineno(node) | ||||||
|  |         level = node.level | ||||||
|  |         if level == 0 and "absolute_import" not in self.futures: | ||||||
|  |             level = -1 | ||||||
|         fromlist = map(lambda (name, alias): name, node.names) |         fromlist = map(lambda (name, alias): name, node.names) | ||||||
|         if VERSION > 1: |         if VERSION > 1: | ||||||
|  |             self.emit('LOAD_CONST', level) | ||||||
|             self.emit('LOAD_CONST', tuple(fromlist)) |             self.emit('LOAD_CONST', tuple(fromlist)) | ||||||
|         self.emit('IMPORT_NAME', node.modname) |         self.emit('IMPORT_NAME', node.modname) | ||||||
|         for name, alias in node.names: |         for name, alias in node.names: | ||||||
|  |  | ||||||
|  | @ -441,18 +441,25 @@ def import_name(self, nodelist): | ||||||
|                       lineno=nodelist[0][2]) |                       lineno=nodelist[0][2]) | ||||||
| 
 | 
 | ||||||
|     def import_from(self, nodelist): |     def import_from(self, nodelist): | ||||||
|         # import_from: 'from' dotted_name 'import' ('*' | |         # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' | | ||||||
|         #    '(' import_as_names ')' | import_as_names) |         #    '(' import_as_names ')' | import_as_names) | ||||||
|         assert nodelist[0][1] == 'from' |         assert nodelist[0][1] == 'from' | ||||||
|         assert nodelist[1][0] == symbol.dotted_name |         idx = 1 | ||||||
|         assert nodelist[2][1] == 'import' |         while nodelist[idx][1] == '.': | ||||||
|         fromname = self.com_dotted_name(nodelist[1]) |             idx += 1 | ||||||
|         if nodelist[3][0] == token.STAR: |         level = idx - 1 | ||||||
|             return From(fromname, [('*', None)], |         if nodelist[idx][0] == symbol.dotted_name: | ||||||
|  |             fromname = self.com_dotted_name(nodelist[idx]) | ||||||
|  |             idx += 1 | ||||||
|  |         else: | ||||||
|  |             fromname = "" | ||||||
|  |         assert nodelist[idx][1] == 'import' | ||||||
|  |         if nodelist[idx + 1][0] == token.STAR: | ||||||
|  |             return From(fromname, [('*', None)], level, | ||||||
|                         lineno=nodelist[0][2]) |                         lineno=nodelist[0][2]) | ||||||
|         else: |         else: | ||||||
|             node = nodelist[3 + (nodelist[3][0] == token.LPAR)] |             node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token.LPAR)] | ||||||
|             return From(fromname, self.com_import_as_names(node), |             return From(fromname, self.com_import_as_names(node), level, | ||||||
|                         lineno=nodelist[0][2]) |                         lineno=nodelist[0][2]) | ||||||
| 
 | 
 | ||||||
|     def global_stmt(self, nodelist): |     def global_stmt(self, nodelist): | ||||||
|  | @ -575,12 +582,25 @@ def testlist_gexp(self, nodelist): | ||||||
|         return self.testlist(nodelist) |         return self.testlist(nodelist) | ||||||
| 
 | 
 | ||||||
|     def test(self, nodelist): |     def test(self, nodelist): | ||||||
|  |         # or_test ['if' or_test 'else' test] | lambdef | ||||||
|  |         if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: | ||||||
|  |             return self.lambdef(nodelist[0]) | ||||||
|  |         then = self.com_node(nodelist[0]) | ||||||
|  |         if len(nodelist) > 1: | ||||||
|  |             assert len(nodelist) == 5 | ||||||
|  |             assert nodelist[1][1] == 'if' | ||||||
|  |             assert nodelist[3][1] == 'else' | ||||||
|  |             test = self.com_node(nodelist[2]) | ||||||
|  |             else_ = self.com_node(nodelist[4]) | ||||||
|  |             return IfExp(test, then, else_, lineno=nodelist[1][2]) | ||||||
|  |         return then | ||||||
|  | 
 | ||||||
|  |     def or_test(self, nodelist): | ||||||
|         # and_test ('or' and_test)* | lambdef |         # and_test ('or' and_test)* | lambdef | ||||||
|         if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: |         if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef: | ||||||
|             return self.lambdef(nodelist[0]) |             return self.lambdef(nodelist[0]) | ||||||
|         return self.com_binary(Or, nodelist) |         return self.com_binary(Or, nodelist) | ||||||
|     or_test = test |     old_test = or_test | ||||||
|     old_test = test |  | ||||||
| 
 | 
 | ||||||
|     def and_test(self, nodelist): |     def and_test(self, nodelist): | ||||||
|         # not_test ('and' not_test)* |         # not_test ('and' not_test)* | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thomas Wouters
						Thomas Wouters