[Python-checkins] r42812 - python/trunk/Lib/compiler/ast.py python/trunk/Lib/compiler/consts.py python/trunk/Lib/compiler/pyassem.py python/trunk/Lib/compiler/pycodegen.py python/trunk/Lib/compiler/transformer.py

thomas.wouters python-checkins at python.org
Fri Mar 3 19:16:20 CET 2006


Author: thomas.wouters
Date: Fri Mar  3 19:16:20 2006
New Revision: 42812

Modified:
   python/trunk/Lib/compiler/ast.py
   python/trunk/Lib/compiler/consts.py
   python/trunk/Lib/compiler/pyassem.py
   python/trunk/Lib/compiler/pycodegen.py
   python/trunk/Lib/compiler/transformer.py
Log:

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.



Modified: python/trunk/Lib/compiler/ast.py
==============================================================================
--- python/trunk/Lib/compiler/ast.py	(original)
+++ python/trunk/Lib/compiler/ast.py	Fri Mar  3 19:16:20 2006
@@ -524,19 +524,20 @@
         return "For(%s, %s, %s, %s)" % (repr(self.assign), repr(self.list), repr(self.body), repr(self.else_))
 
 class From(Node):
-    def __init__(self, modname, names, lineno=None):
+    def __init__(self, modname, names, level, lineno=None):
         self.modname = modname
         self.names = names
+        self.level = level
         self.lineno = lineno
 
     def getChildren(self):
-        return self.modname, self.names
+        return self.modname, self.names, self.level
 
     def getChildNodes(self):
         return ()
 
     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):
     def __init__(self, decorators, name, argnames, defaults, flags, doc, code, lineno=None):
@@ -553,7 +554,7 @@
             self.varargs = 1
         if flags & CO_VARKEYWORDS:
             self.kwargs = 1
-
+    
 
 
     def getChildren(self):
@@ -584,7 +585,7 @@
         self.lineno = lineno
         self.argnames = ['[outmost-iterable]']
         self.varargs = self.kwargs = None
-
+    
 
 
     def getChildren(self):
@@ -708,6 +709,22 @@
     def __repr__(self):
         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):
     def __init__(self, names, lineno=None):
         self.names = names
@@ -763,7 +780,7 @@
             self.varargs = 1
         if flags & CO_VARKEYWORDS:
             self.kwargs = 1
-
+    
 
 
     def getChildren(self):

Modified: python/trunk/Lib/compiler/consts.py
==============================================================================
--- python/trunk/Lib/compiler/consts.py	(original)
+++ python/trunk/Lib/compiler/consts.py	Fri Mar  3 19:16:20 2006
@@ -17,3 +17,5 @@
 CO_GENERATOR = 0x0020
 CO_GENERATOR_ALLOWED = 0x1000
 CO_FUTURE_DIVISION = 0x2000
+CO_FUTURE_ABSIMPORT = 0x4000
+CO_FUTURE_WITH_STATEMENT = 0x8000

Modified: python/trunk/Lib/compiler/pyassem.py
==============================================================================
--- python/trunk/Lib/compiler/pyassem.py	(original)
+++ python/trunk/Lib/compiler/pyassem.py	Fri Mar  3 19:16:20 2006
@@ -771,7 +771,7 @@
         'COMPARE_OP': -1,
         'STORE_FAST': -1,
         'IMPORT_STAR': -1,
-        'IMPORT_NAME': 0,
+        'IMPORT_NAME': -1,
         'IMPORT_FROM': 1,
         'LOAD_ATTR': 0, # unlike other loads
         # close enough...

Modified: python/trunk/Lib/compiler/pycodegen.py
==============================================================================
--- python/trunk/Lib/compiler/pycodegen.py	(original)
+++ python/trunk/Lib/compiler/pycodegen.py	Fri Mar  3 19:16:20 2006
@@ -8,8 +8,9 @@
 from compiler import ast, parse, walk, syntax
 from compiler import pyassem, misc, future, symbols
 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
-from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\
-     CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION
+from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
+     CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION,
+     CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT)
 from compiler.pyassem import TupleArg
 
 # XXX The version-specific code can go, since this code only works with 2.x.
@@ -215,6 +216,10 @@
                 self._div_op = "BINARY_TRUE_DIVIDE"
             elif feature == "generators":
                 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):
         """This method is called once for each class"""
@@ -543,6 +548,19 @@
     def visitOr(self, node):
         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):
         self.visit(node.expr)
         cleanup = self.newBlock()
@@ -875,8 +893,10 @@
 
     def visitImport(self, node):
         self.set_lineno(node)
+        level = 0 if "absolute_import" in self.futures else -1
         for name, alias in node.names:
             if VERSION > 1:
+                self.emit('LOAD_CONST', level)
                 self.emit('LOAD_CONST', None)
             self.emit('IMPORT_NAME', name)
             mod = name.split(".")[0]
@@ -888,8 +908,12 @@
 
     def visitFrom(self, 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)
         if VERSION > 1:
+            self.emit('LOAD_CONST', level)
             self.emit('LOAD_CONST', tuple(fromlist))
         self.emit('IMPORT_NAME', node.modname)
         for name, alias in node.names:

Modified: python/trunk/Lib/compiler/transformer.py
==============================================================================
--- python/trunk/Lib/compiler/transformer.py	(original)
+++ python/trunk/Lib/compiler/transformer.py	Fri Mar  3 19:16:20 2006
@@ -441,18 +441,25 @@
                       lineno=nodelist[0][2])
 
     def import_from(self, nodelist):
-        # import_from: 'from' dotted_name 'import' ('*' |
+        # import_from: 'from' ('.'* dotted_name | '.') 'import' ('*' |
         #    '(' import_as_names ')' | import_as_names)
         assert nodelist[0][1] == 'from'
-        assert nodelist[1][0] == symbol.dotted_name
-        assert nodelist[2][1] == 'import'
-        fromname = self.com_dotted_name(nodelist[1])
-        if nodelist[3][0] == token.STAR:
-            return From(fromname, [('*', None)],
+        idx = 1
+        while nodelist[idx][1] == '.':
+            idx += 1
+        level = idx - 1
+        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])
         else:
-            node = nodelist[3 + (nodelist[3][0] == token.LPAR)]
-            return From(fromname, self.com_import_as_names(node),
+            node = nodelist[idx + 1 + (nodelist[idx + 1][0] == token.LPAR)]
+            return From(fromname, self.com_import_as_names(node), level,
                         lineno=nodelist[0][2])
 
     def global_stmt(self, nodelist):
@@ -575,12 +582,25 @@
         return self.testlist(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
         if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
             return self.lambdef(nodelist[0])
         return self.com_binary(Or, nodelist)
-    or_test = test
-    old_test = test
+    old_test = or_test
 
     def and_test(self, nodelist):
         # not_test ('and' not_test)*


More information about the Python-checkins mailing list