From 92f397209055a0ae7599e5a7ea202f19fae8fd7b Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Fri, 1 Sep 2000 20:47:37 +0000 Subject: [PATCH] patch by Neil Schemenauer to improve (fix?) line number generation --- Lib/compiler/pyassem.py | 41 ++++++++++++++++++---------- Lib/compiler/pycodegen.py | 8 ++++-- Tools/compiler/compiler/pyassem.py | 41 ++++++++++++++++++---------- Tools/compiler/compiler/pycodegen.py | 8 ++++-- 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/Lib/compiler/pyassem.py b/Lib/compiler/pyassem.py index c8d9e90cc87..74ea562f44e 100644 --- a/Lib/compiler/pyassem.py +++ b/Lib/compiler/pyassem.py @@ -419,21 +419,32 @@ class LineAddrTable: # compute deltas addr = self.codeOffset - self.lastoff line = lineno - self.lastline - while addr > 0 or line > 0: - # write the values in 1-byte chunks that sum - # to desired value - trunc_addr = addr - trunc_line = line - if trunc_addr > 255: - trunc_addr = 255 - if trunc_line > 255: - trunc_line = 255 - self.lnotab.append(trunc_addr) - self.lnotab.append(trunc_line) - addr = addr - trunc_addr - line = line - trunc_line - self.lastline = lineno - self.lastoff = self.codeOffset + # Python assumes that lineno always increases with + # increasing bytecode address (lnotab is unsigned char). + # Depending on when SET_LINENO instructions are emitted + # this is not always true. Consider the code: + # a = (1, + # b) + # In the bytecode stream, the assignment to "a" occurs + # after the loading of "b". This works with the C Python + # compiler because it only generates a SET_LINENO instruction + # for the assignment. + if line > 0: + while addr > 0 or line > 0: + # write the values in 1-byte chunks that sum + # to desired value + trunc_addr = addr + trunc_line = line + if trunc_addr > 255: + trunc_addr = 255 + if trunc_line > 255: + trunc_line = 255 + self.lnotab.append(trunc_addr) + self.lnotab.append(trunc_line) + addr = addr - trunc_addr + line = line - trunc_line + self.lastline = lineno + self.lastoff = self.codeOffset def getCode(self): return string.join(self.code, '') diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py index a4c9e5b18f5..2a1b3081c66 100644 --- a/Lib/compiler/pycodegen.py +++ b/Lib/compiler/pycodegen.py @@ -70,6 +70,7 @@ class CodeGenerator: self.loops = misc.Stack() self.curStack = 0 self.maxStack = 0 + self.last_lineno = None self._setupGraphDelegation() def _setupGraphDelegation(self): @@ -107,7 +108,8 @@ class CodeGenerator: self.emit(prefix + '_GLOBAL', name) def set_lineno(self, node): - """Emit SET_LINENO if node has lineno attribute + """Emit SET_LINENO if node has lineno attribute and it is + different than the last lineno emitted. Returns true if SET_LINENO was emitted. @@ -117,8 +119,9 @@ class CodeGenerator: then, this method works around missing line numbers. """ lineno = getattr(node, 'lineno', None) - if lineno is not None: + if lineno is not None and lineno != self.last_lineno: self.emit('SET_LINENO', lineno) + self.last_lineno = lineno return 1 return 0 @@ -414,6 +417,7 @@ class CodeGenerator: pass def visitName(self, node): + self.set_lineno(node) self.loadName(node.name) def visitPass(self, node): diff --git a/Tools/compiler/compiler/pyassem.py b/Tools/compiler/compiler/pyassem.py index c8d9e90cc87..74ea562f44e 100644 --- a/Tools/compiler/compiler/pyassem.py +++ b/Tools/compiler/compiler/pyassem.py @@ -419,21 +419,32 @@ class LineAddrTable: # compute deltas addr = self.codeOffset - self.lastoff line = lineno - self.lastline - while addr > 0 or line > 0: - # write the values in 1-byte chunks that sum - # to desired value - trunc_addr = addr - trunc_line = line - if trunc_addr > 255: - trunc_addr = 255 - if trunc_line > 255: - trunc_line = 255 - self.lnotab.append(trunc_addr) - self.lnotab.append(trunc_line) - addr = addr - trunc_addr - line = line - trunc_line - self.lastline = lineno - self.lastoff = self.codeOffset + # Python assumes that lineno always increases with + # increasing bytecode address (lnotab is unsigned char). + # Depending on when SET_LINENO instructions are emitted + # this is not always true. Consider the code: + # a = (1, + # b) + # In the bytecode stream, the assignment to "a" occurs + # after the loading of "b". This works with the C Python + # compiler because it only generates a SET_LINENO instruction + # for the assignment. + if line > 0: + while addr > 0 or line > 0: + # write the values in 1-byte chunks that sum + # to desired value + trunc_addr = addr + trunc_line = line + if trunc_addr > 255: + trunc_addr = 255 + if trunc_line > 255: + trunc_line = 255 + self.lnotab.append(trunc_addr) + self.lnotab.append(trunc_line) + addr = addr - trunc_addr + line = line - trunc_line + self.lastline = lineno + self.lastoff = self.codeOffset def getCode(self): return string.join(self.code, '') diff --git a/Tools/compiler/compiler/pycodegen.py b/Tools/compiler/compiler/pycodegen.py index a4c9e5b18f5..2a1b3081c66 100644 --- a/Tools/compiler/compiler/pycodegen.py +++ b/Tools/compiler/compiler/pycodegen.py @@ -70,6 +70,7 @@ class CodeGenerator: self.loops = misc.Stack() self.curStack = 0 self.maxStack = 0 + self.last_lineno = None self._setupGraphDelegation() def _setupGraphDelegation(self): @@ -107,7 +108,8 @@ class CodeGenerator: self.emit(prefix + '_GLOBAL', name) def set_lineno(self, node): - """Emit SET_LINENO if node has lineno attribute + """Emit SET_LINENO if node has lineno attribute and it is + different than the last lineno emitted. Returns true if SET_LINENO was emitted. @@ -117,8 +119,9 @@ class CodeGenerator: then, this method works around missing line numbers. """ lineno = getattr(node, 'lineno', None) - if lineno is not None: + if lineno is not None and lineno != self.last_lineno: self.emit('SET_LINENO', lineno) + self.last_lineno = lineno return 1 return 0 @@ -414,6 +417,7 @@ class CodeGenerator: pass def visitName(self, node): + self.set_lineno(node) self.loadName(node.name) def visitPass(self, node):