summaryrefslogtreecommitdiffstats
path: root/lldb/scripts/Python/modify-python-lldb.py
blob: 2881d4ead62b61b71d3f435423e74dccf45e8e3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#
# modify-python-lldb.py
#
# This script modifies the lldb module (which was automatically generated via
# running swig) to support iteration and/or equality operations for certain lldb
# objects, implements truth value testing for certain lldb objects, and adds a
# global variable 'debugger_unique_id' which is initialized to 0.
#
# As a cleanup step, it also removes the 'residues' from the autodoc features of
# swig.  For an example, take a look at SBTarget.h header file, where we take
# advantage of the already existing doxygen C++-docblock and make it the Python
# docstring for the same method.  The 'residues' in this context include the c
# comment marker, the trailing blank (SPC's) line, and the doxygen comment start
# marker.
#
# In addition to the 'residues' removal during the cleanup step, it also
# transforms the 'char' data type (which was actually 'char *' but the 'autodoc'
# feature of swig removes ' *' from it) into 'str' (as a Python str type).

# System modules
import sys
import re
if sys.version_info.major >= 3:
    import io as StringIO
else:
    import StringIO

# import use_lldb_suite so we can find third-party and helper modules
import use_lldb_suite

# Third party modules
import six

# LLDB modules

if len(sys.argv) != 2:
    output_name = "./lldb.py"
else:
    output_name = sys.argv[1] + "/lldb.py"

# print "output_name is '" + output_name + "'"

#
# Residues to be removed.
#
# The demarcation point for turning on/off residue removal state.
# When bracketed by the lines, the CLEANUP_DOCSTRING state (see below) is ON.
toggle_docstring_cleanup_line = '        """'


def char_to_str_xform(line):
    """This transforms the 'char', i.e, 'char *' to 'str', Python string."""
    line = line.replace(' char', ' str')
    line = line.replace('char ', 'str ')
    # Special case handling of 'char **argv' and 'char **envp'.
    line = line.replace('str argv', 'list argv')
    line = line.replace('str envp', 'list envp')
    return line

#
# The one-liner docstring also needs char_to_str transformation, btw.
#
TWO_SPACES = ' ' * 2
EIGHT_SPACES = ' ' * 8
one_liner_docstring_pattern = re.compile(
    '^(%s|%s)""".*"""$' %
    (TWO_SPACES, EIGHT_SPACES))

class NewContent(StringIO.StringIO):
    """Simple facade to keep track of the previous line to be committed."""

    def __init__(self):
        StringIO.StringIO.__init__(self)
        self.prev_line = None

    def add_line(self, a_line):
        """Add a line to the content, if there is a previous line, commit it."""
        if self.prev_line is not None:
            self.write(self.prev_line + "\n")
        self.prev_line = a_line

    def del_line(self):
        """Forget about the previous line, do not commit it."""
        self.prev_line = None

    def del_blank_line(self):
        """Forget about the previous line if it is a blank line."""
        if self.prev_line is not None and not self.prev_line.strip():
            self.prev_line = None

    def finish(self):
        """Call this when you're finished with populating content."""
        if self.prev_line is not None:
            self.write(self.prev_line + "\n")
        self.prev_line = None

# The new content will have the iteration protocol defined for our lldb
# objects.
new_content = NewContent()

with open(output_name, 'r') as f_in:
    content = f_in.read()

# These define the states of our finite state machine.
NORMAL = 1
CLEANUP_DOCSTRING = 8

# Our FSM begins its life in the NORMAL state.  The state CLEANUP_DOCSTRING can
# be entered from the NORMAL.  While in this state, the FSM is fixing/cleaning
# the Python docstrings generated by the swig docstring features.
state = NORMAL

for line in content.splitlines():
    # If '        """' is the sole line, prepare to transition to the
    # CLEANUP_DOCSTRING state or out of it.

    if line == toggle_docstring_cleanup_line:
        if state & CLEANUP_DOCSTRING:
            state ^= CLEANUP_DOCSTRING
        else:
            state |= CLEANUP_DOCSTRING

    if (state & CLEANUP_DOCSTRING):
        # Remove the '\a ' and '\b 'substrings.
        line = line.replace('\a ', '')
        line = line.replace('\b ', '')

        line = char_to_str_xform(line)

        # Note that the transition out of CLEANUP_DOCSTRING is handled at the
        # beginning of this function already.

    # This deals with one-liner docstring, for example, SBThread.GetName:
    # """GetName(self) -> char""".
    if one_liner_docstring_pattern.match(line):
        line = char_to_str_xform(line)

    # Pass the original line of content to new_content.
    new_content.add_line(line)

# We are finished with recording new content.
new_content.finish()

with open(output_name, 'w') as f_out:
    f_out.write(new_content.getvalue())
OpenPOWER on IntegriCloud