Commits

Rick Copeland committed 04885c3

Add missing files for debug support

  • Participants
  • Parent commits 19ea0b1

Comments (0)

Files changed (2)

File kajiki/lnotab.py

+# Comment copied from Python/compile.c:
+#
+# All about a_lnotab.
+# 
+# c_lnotab is an array of unsigned bytes disguised as a Python string.
+# It is used to map bytecode offsets to source code line #s (when needed
+# for tracebacks).
+# 
+# The array is conceptually a list of
+#     (bytecode offset increment, line number increment)
+# pairs. The details are important and delicate, best illustrated by example:
+# 
+#     byte code offset   source code line number
+#        0                   1
+#        6                   2
+#       50                   7
+#      350                 307
+#      361                 308
+# 
+# The first trick is that these numbers aren't stored, only the increments
+# from one row to the next (this doesn't really work, but it's a start):
+# 
+#     0, 1,  6, 1,  44, 5,  300, 300,  11, 1
+# 
+# The second trick is that an unsigned byte can't hold negative values, or
+# values larger than 255, so (a) there's a deep assumption that byte code
+# offsets and their corresponding line #s both increase monotonically, and (b)
+# if at least one column jumps by more than 255 from one row to the next, more
+# than one pair is written to the table. In case #b, there's no way to know
+# from looking at the table later how many were written.	That's the delicate
+# part.  A user of c_lnotab desiring to find the source line number
+# corresponding to a bytecode address A should do something like this
+# 
+#     lineno = addr = 0
+#     for addr_incr, line_incr in c_lnotab:
+#         addr += addr_incr
+#         if addr > A:
+#             return lineno
+#         lineno += line_incr
+# 
+# In order for this to work, when the addr field increments by more than 255,
+# the line # increment in each pair generated must be 0 until the remaining addr
+# increment is < 256.  So, in the example above, assemble_lnotab (it used
+# to be called com_set_lineno) should not (as was actually done until 2.2)
+# expand 300, 300 to 255, 255, 45, 45, 
+#             but to 255,   0, 45, 255, 0, 45.
+# 
+
+def lnotab(pairs, first_lineno=0):
+    """Yields byte integers representing the pairs of integers passed in."""
+    assert first_lineno <= pairs[0][1]
+    cur_byte, cur_line = 0, first_lineno
+    for byte_off, line_off in pairs:
+        byte_delta = byte_off - cur_byte
+        line_delta = line_off - cur_line
+        assert byte_delta >= 0
+        assert line_delta >= 0
+        while byte_delta > 255:
+            yield 255 # byte
+            yield 0   # line
+            byte_delta -= 255
+        yield byte_delta
+        while line_delta > 255:
+            yield 255 # line
+            yield 0   # byte
+            line_delta -= 255
+        yield line_delta
+        cur_byte, cur_line = byte_off, line_off
+
+def lnotab_string(pairs, first_lineno=0):
+    return "".join(chr(b) for b in lnotab(pairs, first_lineno))
+
+def byte_pairs(lnotab):
+    """Yield pairs of integers from a string."""
+    for i in range(0, len(lnotab), 2):
+        yield ord(lnotab[i]), ord(lnotab[i+1])
+        
+def lnotab_numbers(lnotab, first_lineno=0):
+    """Yields the byte, line offset pairs from a packed lnotab string."""
+
+    last_line = None
+    cur_byte, cur_line = 0, first_lineno
+    for byte_delta, line_delta in byte_pairs(lnotab):
+        if byte_delta:
+            if cur_line != last_line:
+                yield cur_byte, cur_line
+                last_line = cur_line
+            cur_byte += byte_delta
+        cur_line += line_delta
+    if cur_line != last_line:        
+        yield cur_byte, cur_line

File kajiki/tests/data/debug.html

+<div>
+  <py:def function="one()">${two()}</py:def>
+  <py:def function="two()">${three()}</py:def>
+  <py:def function="three()">
+    <?py raise ValueError, 'Test error' ?>
+  </py:def>
+  ${one()}
+</div>