summaryrefslogtreecommitdiff
path: root/lab/parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'lab/parser.py')
-rw-r--r--lab/parser.py79
1 files changed, 55 insertions, 24 deletions
diff --git a/lab/parser.py b/lab/parser.py
index 1a679e8c..5e5b4b36 100644
--- a/lab/parser.py
+++ b/lab/parser.py
@@ -5,9 +5,13 @@
from __future__ import division
-import glob, os, sys
import collections
-from optparse import OptionParser
+import glob
+import optparse
+import os
+import re
+import sys
+import textwrap
import disgen
@@ -24,7 +28,7 @@ class ParserMain(object):
def main(self, args):
"""A main function for trying the code from the command line."""
- parser = OptionParser()
+ parser = optparse.OptionParser()
parser.add_option(
"-c", action="store_true", dest="chunks",
help="Show basic block chunks"
@@ -72,9 +76,21 @@ class ParserMain(object):
def one_file(self, options, filename):
"""Process just one file."""
+ # `filename` can have a line number suffix. In that case, extract those
+ # lines, dedent them, and use that. This is for trying test cases
+ # embedded in the test files.
+ match = re.search(r"^(.*):(\d+)-(\d+)$", filename)
+ if match:
+ filename, start, end = match.groups()
+ start, end = int(start), int(end)
+ else:
+ start = end = None
try:
text = get_python_source(filename)
+ if start is not None:
+ lines = text.splitlines(True)
+ text = textwrap.dedent("".join(lines[start-1:end]).replace("\\\\", "\\"))
bp = ByteParser(text, filename=filename)
except Exception as err:
print("%s" % (err,))
@@ -82,7 +98,7 @@ class ParserMain(object):
if options.dis:
print("Main code:")
- self.disassemble(bp, histogram=options.histogram)
+ self.disassemble(bp, chunks=options.chunks, histogram=options.histogram)
arcs = bp._all_arcs()
if options.chunks:
@@ -109,29 +125,37 @@ class ParserMain(object):
exit_counts = cp.exit_counts()
for lineno, ltext in enumerate(cp.lines, start=1):
- m0 = m1 = m2 = m3 = a = ' '
+ marks = [' ', ' ', ' ', ' ', ' ']
+ a = ' '
+ if lineno in cp.raw_statements:
+ marks[0] = '-'
if lineno in cp.statements:
- m0 = '='
- elif lineno in cp.raw_statements:
- m0 = '-'
+ marks[1] = '='
exits = exit_counts.get(lineno, 0)
if exits > 1:
- m1 = str(exits)
+ marks[2] = str(exits)
if lineno in cp.raw_docstrings:
- m2 = '"'
+ marks[3] = '"'
if lineno in cp.raw_classdefs:
- m2 = 'C'
+ marks[3] = 'C'
+ if lineno in cp.raw_funcdefs:
+ marks[3] = 'f'
if lineno in cp.raw_excluded:
- m3 = 'x'
- a = arc_chars[lineno].ljust(arc_width)
- print("%4d %s%s%s%s%s %s" % (lineno, m0, m1, m2, m3, a, ltext))
+ marks[4] = 'x'
+
+ if arc_chars:
+ a = arc_chars[lineno].ljust(arc_width)
+ else:
+ a = ""
- def disassemble(self, byte_parser, histogram=False):
+ print("%4d %s%s %s" % (lineno, "".join(marks), a, ltext))
+
+ def disassemble(self, byte_parser, chunks=False, histogram=False):
"""Disassemble code, for ad-hoc experimenting."""
for bp in byte_parser.child_parsers():
- chunks = bp._split_into_chunks()
- chunkd = dict((chunk.byte, chunk) for chunk in chunks)
+ if chunks:
+ chunkd = dict((chunk.byte, chunk) for chunk in bp._split_into_chunks())
if bp.text:
srclines = bp.text.splitlines()
else:
@@ -151,11 +175,11 @@ class ParserMain(object):
elif disline.offset > 0:
print("")
line = disgen.format_dis_line(disline)
- chunk = chunkd.get(disline.offset)
- if chunk:
- chunkstr = ":: %r" % chunk
- else:
- chunkstr = ""
+ chunkstr = ""
+ if chunks:
+ chunk = chunkd.get(disline.offset)
+ if chunk:
+ chunkstr = ":: %r" % chunk
print("%-70s%s" % (line, chunkstr))
print("")
@@ -168,6 +192,7 @@ class ParserMain(object):
"""
+ plus_ones = set()
arc_chars = collections.defaultdict(str)
for lfrom, lto in sorted(arcs):
if lfrom < 0:
@@ -176,13 +201,12 @@ class ParserMain(object):
arc_chars[lfrom] += '^'
else:
if lfrom == lto - 1:
- # Don't show obvious arcs.
+ plus_ones.add(lfrom)
continue
if lfrom < lto:
l1, l2 = lfrom, lto
else:
l1, l2 = lto, lfrom
- #w = max(len(arc_chars[l]) for l in range(l1, l2+1))
w = first_all_blanks(arc_chars[l] for l in range(l1, l2+1))
for l in range(l1, l2+1):
if l == lfrom:
@@ -193,6 +217,13 @@ class ParserMain(object):
ch = '|'
arc_chars[l] = set_char(arc_chars[l], w, ch)
+ # Add the plusses as the first character
+ for lineno, arcs in arc_chars.items():
+ arc_chars[lineno] = (
+ ("+" if lineno in plus_ones else " ") +
+ arcs
+ )
+
return arc_chars