]> granicus.if.org Git - python/commitdiff
add loop handling via
authorJeremy Hylton <jeremy@alum.mit.edu>
Thu, 10 Feb 2000 20:55:50 +0000 (20:55 +0000)
committerJeremy Hylton <jeremy@alum.mit.edu>
Thu, 10 Feb 2000 20:55:50 +0000 (20:55 +0000)
Loop object to handle StackRegs
loops stack attr on CodeGenreeator to hold the current loop object

add support for nodes While, Break, Continue

Lib/compiler/pycodegen.py
Tools/compiler/compiler/pycodegen.py

index 92cbef67212f75bde0fd5b4b2e3b789fc8eebbf7..66dd52ddae83e09bb2c712f20d5457be9912a63d 100644 (file)
@@ -162,6 +162,7 @@ class CodeGenerator:
        self.code = PythonVMCode(filename=filename)
         self.code.setFlags(0)
        self.locals = misc.Stack()
+        self.loops = misc.Stack()
         self.namespace = self.MODULE_NAMESPACE
         self.curStack = 0
         self.maxStack = 0
@@ -180,8 +181,6 @@ class CodeGenerator:
             self.code.setKWArgs()
         lnf = walk(func.code, LocalNameFinder(args), 0)
         self.locals.push(lnf.getLocals())
-##        print func.name, "(", func.argnames, ")"
-##        print lnf.getLocals().items()
        self.code.setLineNo(func.lineno)
         walk(func.code, self)
         self.code.emit('LOAD_CONST', None)
@@ -280,6 +279,8 @@ class CodeGenerator:
         return 1
 
     def visitCallFunc(self, node):
+        if hasattr(node, 'lineno'):
+            self.code.emit('SET_LINENO', node.lineno)
        self.visit(node.node)
        for arg in node.args:
            self.visit(arg)
@@ -306,30 +307,76 @@ class CodeGenerator:
        after.bind(self.code.getCurInst())
        return 1
 
+    def startLoop(self):
+        l = Loop()
+        self.loops.push(l)
+        self.code.emit('SETUP_LOOP', l.extentAnchor)
+        return l
+
+    def finishLoop(self):
+        l = self.loops.pop()
+        i = self.code.getCurInst()
+        l.extentAnchor.bind(self.code.getCurInst())
+
     def visitFor(self, node):
         # three refs needed
-        start = StackRef()
         anchor = StackRef()
-        breakAnchor = StackRef()
 
         self.code.emit('SET_LINENO', node.lineno)
-        self.code.emit('SETUP_LOOP', breakAnchor)
+        l = self.startLoop()
         self.visit(node.list)
         self.visit(ast.Const(0))
-        start.bind(self.code.getCurInst())
+        l.startAnchor.bind(self.code.getCurInst())
         self.code.setLineNo(node.lineno)
         self.code.emit('FOR_LOOP', anchor)
         self.push(1)
         self.visit(node.assign)
         self.visit(node.body)
-        self.code.emit('JUMP_ABSOLUTE', start)
+        self.code.emit('JUMP_ABSOLUTE', l.startAnchor)
         anchor.bind(self.code.getCurInst())
         self.code.emit('POP_BLOCK')
         if node.else_:
             self.visit(node.else_)
-        breakAnchor.bind(self.code.getCurInst())
+        self.finishLoop()
+        return 1
+
+    def visitWhile(self, node):
+        self.code.emit('SET_LINENO', node.lineno)
+        l = self.startLoop()
+        if node.else_:
+            lElse = StackRef()
+        else:
+            lElse = l.breakAnchor
+        l.startAnchor.bind(self.code.getCurInst())
+        self.code.emit('SET_LINENO', node.test.lineno)
+        self.visit(node.test)
+        self.code.emit('JUMP_IF_FALSE', lElse)
+        self.code.emit('POP_TOP')
+        self.visit(node.body)
+        self.code.emit('JUMP_ABSOLUTE', l.startAnchor)
+        # note that lElse may be an alias for l.breakAnchor
+        lElse.bind(self.code.getCurInst())
+        self.code.emit('POP_TOP')
+        self.code.emit('POP_BLOCK')
+        if node.else_:
+            self.visit(node.else_)
+        self.finishLoop()
         return 1
 
+    def visitBreak(self, node):
+        if not self.loops:
+            raise SyntaxError, "'break' outside loop"
+        self.code.emit('SET_LINENO', node.lineno)
+        self.code.emit('BREAK_LOOP')
+
+    def visitContinue(self, node):
+        if not self.loops:
+            raise SyntaxError, "'continue' outside loop"
+        l = self.loops.top()
+        self.code.emit('SET_LINENO', node.lineno)
+        self.code.emit('JUMP_ABSOLUTE', l.startAnchor)
+        
+
     def visitCompare(self, node):
        """Comment from compile.c follows:
 
@@ -617,11 +664,11 @@ class LocalNameFinder:
     def visitAssName(self, node):
        self.names.add(node.name)
 
-class Label:
-    def __init__(self, num):
-       self.num = num
-    def __repr__(self):
-       return "Label(%d)" % self.num
+class Loop:
+    def __init__(self):
+        self.startAnchor = StackRef()
+        self.breakAnchor = StackRef()
+        self.extentAnchor = StackRef()
 
 class StackRef:
     """Manage stack locations for jumps, loops, etc."""
@@ -644,6 +691,9 @@ class StackRef:
        self.val = inst
 
     def resolve(self):
+        if self.val is None:
+            print "UNRESOLVE REF", self
+            return 0
        return self.val
 
 def add_hook(hooks, type, meth):
index 92cbef67212f75bde0fd5b4b2e3b789fc8eebbf7..66dd52ddae83e09bb2c712f20d5457be9912a63d 100644 (file)
@@ -162,6 +162,7 @@ class CodeGenerator:
        self.code = PythonVMCode(filename=filename)
         self.code.setFlags(0)
        self.locals = misc.Stack()
+        self.loops = misc.Stack()
         self.namespace = self.MODULE_NAMESPACE
         self.curStack = 0
         self.maxStack = 0
@@ -180,8 +181,6 @@ class CodeGenerator:
             self.code.setKWArgs()
         lnf = walk(func.code, LocalNameFinder(args), 0)
         self.locals.push(lnf.getLocals())
-##        print func.name, "(", func.argnames, ")"
-##        print lnf.getLocals().items()
        self.code.setLineNo(func.lineno)
         walk(func.code, self)
         self.code.emit('LOAD_CONST', None)
@@ -280,6 +279,8 @@ class CodeGenerator:
         return 1
 
     def visitCallFunc(self, node):
+        if hasattr(node, 'lineno'):
+            self.code.emit('SET_LINENO', node.lineno)
        self.visit(node.node)
        for arg in node.args:
            self.visit(arg)
@@ -306,30 +307,76 @@ class CodeGenerator:
        after.bind(self.code.getCurInst())
        return 1
 
+    def startLoop(self):
+        l = Loop()
+        self.loops.push(l)
+        self.code.emit('SETUP_LOOP', l.extentAnchor)
+        return l
+
+    def finishLoop(self):
+        l = self.loops.pop()
+        i = self.code.getCurInst()
+        l.extentAnchor.bind(self.code.getCurInst())
+
     def visitFor(self, node):
         # three refs needed
-        start = StackRef()
         anchor = StackRef()
-        breakAnchor = StackRef()
 
         self.code.emit('SET_LINENO', node.lineno)
-        self.code.emit('SETUP_LOOP', breakAnchor)
+        l = self.startLoop()
         self.visit(node.list)
         self.visit(ast.Const(0))
-        start.bind(self.code.getCurInst())
+        l.startAnchor.bind(self.code.getCurInst())
         self.code.setLineNo(node.lineno)
         self.code.emit('FOR_LOOP', anchor)
         self.push(1)
         self.visit(node.assign)
         self.visit(node.body)
-        self.code.emit('JUMP_ABSOLUTE', start)
+        self.code.emit('JUMP_ABSOLUTE', l.startAnchor)
         anchor.bind(self.code.getCurInst())
         self.code.emit('POP_BLOCK')
         if node.else_:
             self.visit(node.else_)
-        breakAnchor.bind(self.code.getCurInst())
+        self.finishLoop()
+        return 1
+
+    def visitWhile(self, node):
+        self.code.emit('SET_LINENO', node.lineno)
+        l = self.startLoop()
+        if node.else_:
+            lElse = StackRef()
+        else:
+            lElse = l.breakAnchor
+        l.startAnchor.bind(self.code.getCurInst())
+        self.code.emit('SET_LINENO', node.test.lineno)
+        self.visit(node.test)
+        self.code.emit('JUMP_IF_FALSE', lElse)
+        self.code.emit('POP_TOP')
+        self.visit(node.body)
+        self.code.emit('JUMP_ABSOLUTE', l.startAnchor)
+        # note that lElse may be an alias for l.breakAnchor
+        lElse.bind(self.code.getCurInst())
+        self.code.emit('POP_TOP')
+        self.code.emit('POP_BLOCK')
+        if node.else_:
+            self.visit(node.else_)
+        self.finishLoop()
         return 1
 
+    def visitBreak(self, node):
+        if not self.loops:
+            raise SyntaxError, "'break' outside loop"
+        self.code.emit('SET_LINENO', node.lineno)
+        self.code.emit('BREAK_LOOP')
+
+    def visitContinue(self, node):
+        if not self.loops:
+            raise SyntaxError, "'continue' outside loop"
+        l = self.loops.top()
+        self.code.emit('SET_LINENO', node.lineno)
+        self.code.emit('JUMP_ABSOLUTE', l.startAnchor)
+        
+
     def visitCompare(self, node):
        """Comment from compile.c follows:
 
@@ -617,11 +664,11 @@ class LocalNameFinder:
     def visitAssName(self, node):
        self.names.add(node.name)
 
-class Label:
-    def __init__(self, num):
-       self.num = num
-    def __repr__(self):
-       return "Label(%d)" % self.num
+class Loop:
+    def __init__(self):
+        self.startAnchor = StackRef()
+        self.breakAnchor = StackRef()
+        self.extentAnchor = StackRef()
 
 class StackRef:
     """Manage stack locations for jumps, loops, etc."""
@@ -644,6 +691,9 @@ class StackRef:
        self.val = inst
 
     def resolve(self):
+        if self.val is None:
+            print "UNRESOLVE REF", self
+            return 0
        return self.val
 
 def add_hook(hooks, type, meth):