Sun, 05 Sep 2010 15:26:43 +0200
Prepared new release.
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
1 | """Code parsing for Coverage.""" |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
2 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
3 | import glob, opcode, os, re, sys, token, tokenize |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
4 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
5 | from .backward import set, sorted, StringIO # pylint: disable-msg=W0622 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
6 | from .bytecode import ByteCodes, CodeObjects |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
7 | from .misc import nice_pair, CoverageException, NoSource, expensive |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
8 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
9 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
10 | class CodeParser(object): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
11 | """Parse code to find executable lines, excluded lines, etc.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
12 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
13 | def __init__(self, text=None, filename=None, exclude=None): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
14 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
15 | Source can be provided as `text`, the text itself, or `filename`, from |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
16 | which text will be read. Excluded lines are those that match |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
17 | `exclude`, a regex. |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
18 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
19 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
20 | assert text or filename, "CodeParser needs either text or filename" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
21 | self.filename = filename or "<code>" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
22 | self.text = text |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
23 | if not self.text: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
24 | try: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
25 | sourcef = open(self.filename, 'rU') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
26 | self.text = sourcef.read() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
27 | sourcef.close() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
28 | except IOError: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
29 | _, err, _ = sys.exc_info() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
30 | raise NoSource( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
31 | "No source for code: %r: %s" % (self.filename, err) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
32 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
33 | self.text = self.text.replace('\r\n', '\n') |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
34 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
35 | self.exclude = exclude |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
36 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
37 | self.show_tokens = False |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
38 | |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
39 | # The text lines of the parsed code. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
40 | self.lines = self.text.split('\n') |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
41 | |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
42 | # The line numbers of excluded lines of code. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
43 | self.excluded = set() |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
44 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
45 | # The line numbers of docstring lines. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
46 | self.docstrings = set() |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
47 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
48 | # The line numbers of class definitions. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
49 | self.classdefs = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
50 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
51 | # A dict mapping line numbers to (lo,hi) for multi-line statements. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
52 | self.multiline = {} |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
53 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
54 | # The line numbers that start statements. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
55 | self.statement_starts = set() |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
56 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
57 | # Lazily-created ByteParser |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
58 | self._byte_parser = None |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
59 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
60 | def _get_byte_parser(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
61 | """Create a ByteParser on demand.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
62 | if not self._byte_parser: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
63 | self._byte_parser = \ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
64 | ByteParser(text=self.text, filename=self.filename) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
65 | return self._byte_parser |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
66 | byte_parser = property(_get_byte_parser) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
67 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
68 | def _raw_parse(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
69 | """Parse the source to find the interesting facts about its lines. |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
70 | |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
71 | A handful of member fields are updated. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
72 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
73 | """ |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
74 | # Find lines which match an exclusion pattern. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
75 | if self.exclude: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
76 | re_exclude = re.compile(self.exclude) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
77 | for i, ltext in enumerate(self.lines): |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
78 | if re_exclude.search(ltext): |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
79 | self.excluded.add(i+1) |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
80 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
81 | # Tokenize, to find excluded suites, to find docstrings, and to find |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
82 | # multi-line statements. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
83 | indent = 0 |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
84 | exclude_indent = 0 |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
85 | excluding = False |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
86 | prev_toktype = token.INDENT |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
87 | first_line = None |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
88 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
89 | tokgen = tokenize.generate_tokens(StringIO(self.text).readline) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
90 | for toktype, ttext, (slineno, _), (elineno, _), ltext in tokgen: |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
91 | if self.show_tokens: # pragma: no cover |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
92 | print("%10s %5s %-20r %r" % ( |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
93 | tokenize.tok_name.get(toktype, toktype), |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
94 | nice_pair((slineno, elineno)), ttext, ltext |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
95 | )) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
96 | if toktype == token.INDENT: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
97 | indent += 1 |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
98 | elif toktype == token.DEDENT: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
99 | indent -= 1 |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
100 | elif toktype == token.NAME and ttext == 'class': |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
101 | # Class definitions look like branches in the byte code, so |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
102 | # we need to exclude them. The simplest way is to note the |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
103 | # lines with the 'class' keyword. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
104 | self.classdefs.add(slineno) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
105 | elif toktype == token.OP and ttext == ':': |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
106 | if not excluding and elineno in self.excluded: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
107 | # Start excluding a suite. We trigger off of the colon |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
108 | # token so that the #pragma comment will be recognized on |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
109 | # the same line as the colon. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
110 | exclude_indent = indent |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
111 | excluding = True |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
112 | elif toktype == token.STRING and prev_toktype == token.INDENT: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
113 | # Strings that are first on an indented line are docstrings. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
114 | # (a trick from trace.py in the stdlib.) This works for |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
115 | # 99.9999% of cases. For the rest (!) see: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
116 | # http://stackoverflow.com/questions/1769332/x/1769794#1769794 |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
117 | for i in range(slineno, elineno+1): |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
118 | self.docstrings.add(i) |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
119 | elif toktype == token.NEWLINE: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
120 | if first_line is not None and elineno != first_line: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
121 | # We're at the end of a line, and we've ended on a |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
122 | # different line than the first line of the statement, |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
123 | # so record a multi-line range. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
124 | rng = (first_line, elineno) |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
125 | for l in range(first_line, elineno+1): |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
126 | self.multiline[l] = rng |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
127 | first_line = None |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
128 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
129 | if ttext.strip() and toktype != tokenize.COMMENT: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
130 | # A non-whitespace token. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
131 | if first_line is None: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
132 | # The token is not whitespace, and is the first in a |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
133 | # statement. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
134 | first_line = slineno |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
135 | # Check whether to end an excluded suite. |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
136 | if excluding and indent <= exclude_indent: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
137 | excluding = False |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
138 | if excluding: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
139 | self.excluded.add(elineno) |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
140 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
141 | prev_toktype = toktype |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
142 | |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
143 | # Find the starts of the executable statements. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
144 | self.statement_starts.update(self.byte_parser._find_statements()) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
145 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
146 | def first_line(self, line): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
147 | """Return the first line number of the statement including `line`.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
148 | rng = self.multiline.get(line) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
149 | if rng: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
150 | first_line = rng[0] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
151 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
152 | first_line = line |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
153 | return first_line |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
154 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
155 | def first_lines(self, lines, ignore=None): |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
156 | """Map the line numbers in `lines` to the correct first line of the |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
157 | statement. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
158 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
159 | Skip any line mentioned in `ignore`. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
160 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
161 | Returns a sorted list of the first lines. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
162 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
163 | """ |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
164 | ignore = ignore or [] |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
165 | lset = set() |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
166 | for l in lines: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
167 | if l in ignore: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
168 | continue |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
169 | new_l = self.first_line(l) |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
170 | if new_l not in ignore: |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
171 | lset.add(new_l) |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
172 | return sorted(lset) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
173 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
174 | def parse_source(self): |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
175 | """Parse source text to find executable lines, excluded lines, etc. |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
176 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
177 | Return values are 1) a sorted list of executable line numbers, and |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
178 | 2) a sorted list of excluded line numbers. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
179 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
180 | Reported line numbers are normalized to the first line of multi-line |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
181 | statements. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
182 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
183 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
184 | self._raw_parse() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
185 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
186 | excluded_lines = self.first_lines(self.excluded) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
187 | ignore = excluded_lines + list(self.docstrings) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
188 | lines = self.first_lines(self.statement_starts, ignore) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
189 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
190 | return lines, excluded_lines |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
191 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
192 | def arcs(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
193 | """Get information about the arcs available in the code. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
194 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
195 | Returns a sorted list of line number pairs. Line numbers have been |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
196 | normalized to the first line of multiline statements. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
197 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
198 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
199 | all_arcs = [] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
200 | for l1, l2 in self.byte_parser._all_arcs(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
201 | fl1 = self.first_line(l1) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
202 | fl2 = self.first_line(l2) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
203 | if fl1 != fl2: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
204 | all_arcs.append((fl1, fl2)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
205 | return sorted(all_arcs) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
206 | arcs = expensive(arcs) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
207 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
208 | def exit_counts(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
209 | """Get a mapping from line numbers to count of exits from that line. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
210 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
211 | Excluded lines are excluded. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
212 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
213 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
214 | excluded_lines = self.first_lines(self.excluded) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
215 | exit_counts = {} |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
216 | for l1, l2 in self.arcs(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
217 | if l1 == -1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
218 | # Don't ever report -1 as a line number |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
219 | continue |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
220 | if l1 in excluded_lines: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
221 | # Don't report excluded lines as line numbers. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
222 | continue |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
223 | if l2 in excluded_lines: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
224 | # Arcs to excluded lines shouldn't count. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
225 | continue |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
226 | if l1 not in exit_counts: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
227 | exit_counts[l1] = 0 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
228 | exit_counts[l1] += 1 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
229 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
230 | # Class definitions have one extra exit, so remove one for each: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
231 | for l in self.classdefs: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
232 | # Ensure key is there: classdefs can include excluded lines. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
233 | if l in exit_counts: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
234 | exit_counts[l] -= 1 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
235 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
236 | return exit_counts |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
237 | exit_counts = expensive(exit_counts) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
238 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
239 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
240 | ## Opcodes that guide the ByteParser. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
241 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
242 | def _opcode(name): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
243 | """Return the opcode by name from the opcode module.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
244 | return opcode.opmap[name] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
245 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
246 | def _opcode_set(*names): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
247 | """Return a set of opcodes by the names in `names`.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
248 | return set([_opcode(name) for name in names]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
249 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
250 | # Opcodes that leave the code object. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
251 | OPS_CODE_END = _opcode_set('RETURN_VALUE') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
252 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
253 | # Opcodes that unconditionally end the code chunk. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
254 | OPS_CHUNK_END = _opcode_set( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
255 | 'JUMP_ABSOLUTE', 'JUMP_FORWARD', 'RETURN_VALUE', 'RAISE_VARARGS', |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
256 | 'BREAK_LOOP', 'CONTINUE_LOOP', |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
257 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
258 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
259 | # Opcodes that push a block on the block stack. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
260 | OPS_PUSH_BLOCK = _opcode_set('SETUP_LOOP', 'SETUP_EXCEPT', 'SETUP_FINALLY') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
261 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
262 | # Block types for exception handling. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
263 | OPS_EXCEPT_BLOCKS = _opcode_set('SETUP_EXCEPT', 'SETUP_FINALLY') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
264 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
265 | # Opcodes that pop a block from the block stack. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
266 | OPS_POP_BLOCK = _opcode_set('POP_BLOCK') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
267 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
268 | # Opcodes that have a jump destination, but aren't really a jump. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
269 | OPS_NO_JUMP = _opcode_set('SETUP_EXCEPT', 'SETUP_FINALLY') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
270 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
271 | # Individual opcodes we need below. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
272 | OP_BREAK_LOOP = _opcode('BREAK_LOOP') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
273 | OP_END_FINALLY = _opcode('END_FINALLY') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
274 | OP_COMPARE_OP = _opcode('COMPARE_OP') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
275 | COMPARE_EXCEPTION = 10 # just have to get this const from the code. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
276 | OP_LOAD_CONST = _opcode('LOAD_CONST') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
277 | OP_RETURN_VALUE = _opcode('RETURN_VALUE') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
278 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
279 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
280 | class ByteParser(object): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
281 | """Parse byte codes to understand the structure of code.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
282 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
283 | def __init__(self, code=None, text=None, filename=None): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
284 | if code: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
285 | self.code = code |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
286 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
287 | if not text: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
288 | assert filename, "If no code or text, need a filename" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
289 | sourcef = open(filename, 'rU') |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
290 | text = sourcef.read() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
291 | sourcef.close() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
292 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
293 | try: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
294 | # Python 2.3 and 2.4 don't like partial last lines, so be sure |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
295 | # the text ends nicely for them. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
296 | self.code = compile(text + '\n', filename, "exec") |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
297 | except SyntaxError: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
298 | _, synerr, _ = sys.exc_info() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
299 | raise CoverageException( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
300 | "Couldn't parse '%s' as Python source: '%s' at line %d" % |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
301 | (filename, synerr.msg, synerr.lineno) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
302 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
303 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
304 | def child_parsers(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
305 | """Iterate over all the code objects nested within this one. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
306 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
307 | The iteration includes `self` as its first value. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
308 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
309 | """ |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
310 | return map(lambda c: ByteParser(code=c), CodeObjects(self.code)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
311 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
312 | # Getting numbers from the lnotab value changed in Py3.0. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
313 | if sys.hexversion >= 0x03000000: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
314 | def _lnotab_increments(self, lnotab): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
315 | """Return a list of ints from the lnotab bytes in 3.x""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
316 | return list(lnotab) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
317 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
318 | def _lnotab_increments(self, lnotab): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
319 | """Return a list of ints from the lnotab string in 2.x""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
320 | return [ord(c) for c in lnotab] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
321 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
322 | def _bytes_lines(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
323 | """Map byte offsets to line numbers in `code`. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
324 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
325 | Uses co_lnotab described in Python/compile.c to map byte offsets to |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
326 | line numbers. Returns a list: [(b0, l0), (b1, l1), ...] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
327 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
328 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
329 | # Adapted from dis.py in the standard library. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
330 | byte_increments = self._lnotab_increments(self.code.co_lnotab[0::2]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
331 | line_increments = self._lnotab_increments(self.code.co_lnotab[1::2]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
332 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
333 | bytes_lines = [] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
334 | last_line_num = None |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
335 | line_num = self.code.co_firstlineno |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
336 | byte_num = 0 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
337 | for byte_incr, line_incr in zip(byte_increments, line_increments): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
338 | if byte_incr: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
339 | if line_num != last_line_num: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
340 | bytes_lines.append((byte_num, line_num)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
341 | last_line_num = line_num |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
342 | byte_num += byte_incr |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
343 | line_num += line_incr |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
344 | if line_num != last_line_num: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
345 | bytes_lines.append((byte_num, line_num)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
346 | return bytes_lines |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
347 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
348 | def _find_statements(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
349 | """Find the statements in `self.code`. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
350 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
351 | Return a set of line numbers that start statements. Recurses into all |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
352 | code objects reachable from `self.code`. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
353 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
354 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
355 | stmts = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
356 | for bp in self.child_parsers(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
357 | # Get all of the lineno information from this code. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
358 | for _, l in bp._bytes_lines(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
359 | stmts.add(l) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
360 | return stmts |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
361 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
362 | def _disassemble(self): # pragma: no cover |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
363 | """Disassemble code, for ad-hoc experimenting.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
364 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
365 | import dis |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
366 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
367 | for bp in self.child_parsers(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
368 | print("\n%s: " % bp.code) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
369 | dis.dis(bp.code) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
370 | print("Bytes lines: %r" % bp._bytes_lines()) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
371 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
372 | print("") |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
373 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
374 | def _split_into_chunks(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
375 | """Split the code object into a list of `Chunk` objects. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
376 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
377 | Each chunk is only entered at its first instruction, though there can |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
378 | be many exits from a chunk. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
379 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
380 | Returns a list of `Chunk` objects. |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
381 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
382 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
383 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
384 | # The list of chunks so far, and the one we're working on. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
385 | chunks = [] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
386 | chunk = None |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
387 | bytes_lines_map = dict(self._bytes_lines()) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
388 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
389 | # The block stack: loops and try blocks get pushed here for the |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
390 | # implicit jumps that can occur. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
391 | # Each entry is a tuple: (block type, destination) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
392 | block_stack = [] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
393 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
394 | # Some op codes are followed by branches that should be ignored. This |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
395 | # is a count of how many ignores are left. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
396 | ignore_branch = 0 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
397 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
398 | # We have to handle the last two bytecodes specially. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
399 | ult = penult = None |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
400 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
401 | for bc in ByteCodes(self.code.co_code): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
402 | # Maybe have to start a new block |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
403 | if bc.offset in bytes_lines_map: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
404 | if chunk: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
405 | chunk.exits.add(bc.offset) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
406 | chunk = Chunk(bc.offset, bytes_lines_map[bc.offset]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
407 | chunks.append(chunk) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
408 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
409 | if not chunk: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
410 | chunk = Chunk(bc.offset) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
411 | chunks.append(chunk) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
412 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
413 | # Look at the opcode |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
414 | if bc.jump_to >= 0 and bc.op not in OPS_NO_JUMP: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
415 | if ignore_branch: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
416 | # Someone earlier wanted us to ignore this branch. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
417 | ignore_branch -= 1 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
418 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
419 | # The opcode has a jump, it's an exit for this chunk. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
420 | chunk.exits.add(bc.jump_to) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
421 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
422 | if bc.op in OPS_CODE_END: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
423 | # The opcode can exit the code object. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
424 | chunk.exits.add(-1) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
425 | if bc.op in OPS_PUSH_BLOCK: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
426 | # The opcode adds a block to the block_stack. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
427 | block_stack.append((bc.op, bc.jump_to)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
428 | if bc.op in OPS_POP_BLOCK: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
429 | # The opcode pops a block from the block stack. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
430 | block_stack.pop() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
431 | if bc.op in OPS_CHUNK_END: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
432 | # This opcode forces the end of the chunk. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
433 | if bc.op == OP_BREAK_LOOP: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
434 | # A break is implicit: jump where the top of the |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
435 | # block_stack points. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
436 | chunk.exits.add(block_stack[-1][1]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
437 | chunk = None |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
438 | if bc.op == OP_END_FINALLY: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
439 | if block_stack: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
440 | # A break that goes through a finally will jump to whatever |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
441 | # block is on top of the stack. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
442 | chunk.exits.add(block_stack[-1][1]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
443 | # For the finally clause we need to find the closest exception |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
444 | # block, and use its jump target as an exit. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
445 | for iblock in range(len(block_stack)-1, -1, -1): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
446 | if block_stack[iblock][0] in OPS_EXCEPT_BLOCKS: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
447 | chunk.exits.add(block_stack[iblock][1]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
448 | break |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
449 | if bc.op == OP_COMPARE_OP and bc.arg == COMPARE_EXCEPTION: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
450 | # This is an except clause. We want to overlook the next |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
451 | # branch, so that except's don't count as branches. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
452 | ignore_branch += 1 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
453 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
454 | penult = ult |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
455 | ult = bc |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
456 | |
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
457 | |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
458 | if chunks: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
459 | # The last two bytecodes could be a dummy "return None" that |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
460 | # shouldn't be counted as real code. Every Python code object seems |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
461 | # to end with a return, and a "return None" is inserted if there |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
462 | # isn't an explicit return in the source. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
463 | if ult and penult: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
464 | if penult.op == OP_LOAD_CONST and ult.op == OP_RETURN_VALUE: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
465 | if self.code.co_consts[penult.arg] is None: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
466 | # This is "return None", but is it dummy? A real line |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
467 | # would be a last chunk all by itself. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
468 | if chunks[-1].byte != penult.offset: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
469 | # Split the last chunk |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
470 | last_chunk = chunks[-1] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
471 | last_chunk.exits.remove(-1) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
472 | last_chunk.exits.add(penult.offset) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
473 | chunk = Chunk(penult.offset) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
474 | chunk.exits.add(-1) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
475 | chunks.append(chunk) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
476 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
477 | # Give all the chunks a length. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
478 | chunks[-1].length = bc.next_offset - chunks[-1].byte |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
479 | for i in range(len(chunks)-1): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
480 | chunks[i].length = chunks[i+1].byte - chunks[i].byte |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
481 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
482 | return chunks |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
483 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
484 | def _arcs(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
485 | """Find the executable arcs in the code. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
486 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
487 | Returns a set of pairs, (from,to). From and to are integer line |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
488 | numbers. If from is -1, then the arc is an entrance into the code |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
489 | object. If to is -1, the arc is an exit from the code object. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
490 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
491 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
492 | chunks = self._split_into_chunks() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
493 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
494 | # A map from byte offsets to chunks jumped into. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
495 | byte_chunks = dict([(c.byte, c) for c in chunks]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
496 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
497 | # Build a map from byte offsets to actual lines reached. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
498 | byte_lines = {-1:[-1]} |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
499 | bytes_to_add = set([c.byte for c in chunks]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
500 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
501 | while bytes_to_add: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
502 | byte_to_add = bytes_to_add.pop() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
503 | if byte_to_add in byte_lines or byte_to_add == -1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
504 | continue |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
505 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
506 | # Which lines does this chunk lead to? |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
507 | bytes_considered = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
508 | bytes_to_consider = [byte_to_add] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
509 | lines = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
510 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
511 | while bytes_to_consider: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
512 | byte = bytes_to_consider.pop() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
513 | bytes_considered.add(byte) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
514 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
515 | # Find chunk for byte |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
516 | try: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
517 | ch = byte_chunks[byte] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
518 | except KeyError: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
519 | for ch in chunks: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
520 | if ch.byte <= byte < ch.byte+ch.length: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
521 | break |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
522 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
523 | # No chunk for this byte! |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
524 | raise Exception("Couldn't find chunk @ %d" % byte) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
525 | byte_chunks[byte] = ch |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
526 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
527 | if ch.line: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
528 | lines.add(ch.line) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
529 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
530 | for ex in ch.exits: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
531 | if ex == -1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
532 | lines.add(-1) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
533 | elif ex not in bytes_considered: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
534 | bytes_to_consider.append(ex) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
535 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
536 | bytes_to_add.update(ch.exits) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
537 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
538 | byte_lines[byte_to_add] = lines |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
539 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
540 | # Figure out for each chunk where the exits go. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
541 | arcs = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
542 | for chunk in chunks: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
543 | if chunk.line: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
544 | for ex in chunk.exits: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
545 | for exit_line in byte_lines[ex]: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
546 | if chunk.line != exit_line: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
547 | arcs.add((chunk.line, exit_line)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
548 | for line in byte_lines[0]: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
549 | arcs.add((-1, line)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
550 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
551 | return arcs |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
552 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
553 | def _all_chunks(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
554 | """Returns a list of `Chunk` objects for this code and its children. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
555 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
556 | See `_split_into_chunks` for details. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
557 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
558 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
559 | chunks = [] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
560 | for bp in self.child_parsers(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
561 | chunks.extend(bp._split_into_chunks()) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
562 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
563 | return chunks |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
564 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
565 | def _all_arcs(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
566 | """Get the set of all arcs in this code object and its children. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
567 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
568 | See `_arcs` for details. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
569 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
570 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
571 | arcs = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
572 | for bp in self.child_parsers(): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
573 | arcs.update(bp._arcs()) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
574 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
575 | return arcs |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
576 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
577 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
578 | class Chunk(object): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
579 | """A sequence of bytecodes with a single entrance. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
580 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
581 | To analyze byte code, we have to divide it into chunks, sequences of byte |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
582 | codes such that each basic block has only one entrance, the first |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
583 | instruction in the block. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
584 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
585 | This is almost the CS concept of `basic block`_, except that we're willing |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
586 | to have many exits from a chunk, and "basic block" is a more cumbersome |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
587 | term. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
588 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
589 | .. _basic block: http://en.wikipedia.org/wiki/Basic_block |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
590 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
591 | An exit of -1 means the chunk can leave the code (return). |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
592 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
593 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
594 | def __init__(self, byte, line=0): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
595 | self.byte = byte |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
596 | self.line = line |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
597 | self.length = 0 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
598 | self.exits = set() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
599 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
600 | def __repr__(self): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
601 | return "<%d+%d @%d %r>" % ( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
602 | self.byte, self.length, self.line, list(self.exits) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
603 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
604 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
605 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
606 | class AdHocMain(object): # pragma: no cover |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
607 | """An ad-hoc main for code parsing experiments.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
608 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
609 | def main(self, args): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
610 | """A main function for trying the code from the command line.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
611 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
612 | from optparse import OptionParser |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
613 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
614 | parser = OptionParser() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
615 | parser.add_option( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
616 | "-c", action="store_true", dest="chunks", |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
617 | help="Show basic block chunks" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
618 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
619 | parser.add_option( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
620 | "-d", action="store_true", dest="dis", |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
621 | help="Disassemble" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
622 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
623 | parser.add_option( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
624 | "-R", action="store_true", dest="recursive", |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
625 | help="Recurse to find source files" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
626 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
627 | parser.add_option( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
628 | "-s", action="store_true", dest="source", |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
629 | help="Show analyzed source" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
630 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
631 | parser.add_option( |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
632 | "-t", action="store_true", dest="tokens", |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
633 | help="Show tokens" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
634 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
635 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
636 | options, args = parser.parse_args() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
637 | if options.recursive: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
638 | if args: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
639 | root = args[0] |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
640 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
641 | root = "." |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
642 | for root, _, _ in os.walk(root): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
643 | for f in glob.glob(root + "/*.py"): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
644 | self.adhoc_one_file(options, f) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
645 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
646 | self.adhoc_one_file(options, args[0]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
647 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
648 | def adhoc_one_file(self, options, filename): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
649 | """Process just one file.""" |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
650 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
651 | if options.dis or options.chunks: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
652 | try: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
653 | bp = ByteParser(filename=filename) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
654 | except CoverageException: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
655 | _, err, _ = sys.exc_info() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
656 | print("%s" % (err,)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
657 | return |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
658 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
659 | if options.dis: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
660 | print("Main code:") |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
661 | bp._disassemble() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
662 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
663 | if options.chunks: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
664 | chunks = bp._all_chunks() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
665 | if options.recursive: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
666 | print("%6d: %s" % (len(chunks), filename)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
667 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
668 | print("Chunks: %r" % chunks) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
669 | arcs = bp._all_arcs() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
670 | print("Arcs: %r" % sorted(arcs)) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
671 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
672 | if options.source or options.tokens: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
673 | cp = CodeParser(filename=filename, exclude=r"no\s*cover") |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
674 | cp.show_tokens = options.tokens |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
675 | cp._raw_parse() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
676 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
677 | if options.source: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
678 | if options.chunks: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
679 | arc_width, arc_chars = self.arc_ascii_art(arcs) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
680 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
681 | arc_width, arc_chars = 0, {} |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
682 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
683 | exit_counts = cp.exit_counts() |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
684 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
685 | for i, ltext in enumerate(cp.lines): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
686 | lineno = i+1 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
687 | m0 = m1 = m2 = m3 = a = ' ' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
688 | if lineno in cp.statement_starts: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
689 | m0 = '-' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
690 | exits = exit_counts.get(lineno, 0) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
691 | if exits > 1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
692 | m1 = str(exits) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
693 | if lineno in cp.docstrings: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
694 | m2 = '"' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
695 | if lineno in cp.classdefs: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
696 | m2 = 'C' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
697 | if lineno in cp.excluded: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
698 | m3 = 'x' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
699 | a = arc_chars.get(lineno, '').ljust(arc_width) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
700 | print("%4d %s%s%s%s%s %s" % |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
701 | (lineno, m0, m1, m2, m3, a, ltext) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
702 | ) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
703 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
704 | def arc_ascii_art(self, arcs): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
705 | """Draw arcs as ascii art. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
706 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
707 | Returns a width of characters needed to draw all the arcs, and a |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
708 | dictionary mapping line numbers to ascii strings to draw for that line. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
709 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
710 | """ |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
711 | arc_chars = {} |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
712 | for lfrom, lto in sorted(arcs): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
713 | if lfrom == -1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
714 | arc_chars[lto] = arc_chars.get(lto, '') + 'v' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
715 | elif lto == -1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
716 | arc_chars[lfrom] = arc_chars.get(lfrom, '') + '^' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
717 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
718 | if lfrom == lto-1: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
719 | # Don't show obvious arcs. |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
720 | continue |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
721 | if lfrom < lto: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
722 | l1, l2 = lfrom, lto |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
723 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
724 | l1, l2 = lto, lfrom |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
725 | w = max([len(arc_chars.get(l, '')) for l in range(l1, l2+1)]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
726 | for l in range(l1, l2+1): |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
727 | if l == lfrom: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
728 | ch = '<' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
729 | elif l == lto: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
730 | ch = '>' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
731 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
732 | ch = '|' |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
733 | arc_chars[l] = arc_chars.get(l, '').ljust(w) + ch |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
734 | arc_width = 0 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
735 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
736 | if arc_chars: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
737 | arc_width = max([len(a) for a in arc_chars.values()]) |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
738 | else: |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
739 | arc_width = 0 |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
740 | |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
741 | return arc_width, arc_chars |
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
742 | |
0
de9c2efb9d02
Started porting eric4 to Python3
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
743 | if __name__ == '__main__': |
29
391dc0bc4ae5
Updated coverage.py to version 3.2.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
0
diff
changeset
|
744 | AdHocMain().main(sys.argv[1:]) |