xref: /aosp_15_r20/bionic/libc/kernel/tools/cpp.py (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*8d67ca89SAndroid Build Coastguard Worker"""A glorified C pre-processor parser."""
3*8d67ca89SAndroid Build Coastguard Worker
4*8d67ca89SAndroid Build Coastguard Workerimport ctypes
5*8d67ca89SAndroid Build Coastguard Workerimport logging
6*8d67ca89SAndroid Build Coastguard Workerimport os
7*8d67ca89SAndroid Build Coastguard Workerimport re
8*8d67ca89SAndroid Build Coastguard Workerimport site
9*8d67ca89SAndroid Build Coastguard Workerimport unittest
10*8d67ca89SAndroid Build Coastguard Workerimport utils
11*8d67ca89SAndroid Build Coastguard Worker
12*8d67ca89SAndroid Build Coastguard Workertop = os.getenv('ANDROID_BUILD_TOP')
13*8d67ca89SAndroid Build Coastguard Workerif top is None:
14*8d67ca89SAndroid Build Coastguard Worker    utils.panic('ANDROID_BUILD_TOP not set.\n')
15*8d67ca89SAndroid Build Coastguard Worker
16*8d67ca89SAndroid Build Coastguard Worker# Set up the env vars for libclang.
17*8d67ca89SAndroid Build Coastguard Workersite.addsitedir(os.path.join(top, 'prebuilts/clang/host/linux-x86/clang-stable/lib/python3/site-packages/'))
18*8d67ca89SAndroid Build Coastguard Worker
19*8d67ca89SAndroid Build Coastguard Workerimport clang.cindex
20*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import conf
21*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import Cursor
22*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import CursorKind
23*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import SourceLocation
24*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import SourceRange
25*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import TokenGroup
26*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import TokenKind
27*8d67ca89SAndroid Build Coastguard Workerfrom clang.cindex import TranslationUnit
28*8d67ca89SAndroid Build Coastguard Worker
29*8d67ca89SAndroid Build Coastguard Worker# Set up LD_LIBRARY_PATH to include libclang.so, libLLVM.so, and etc.
30*8d67ca89SAndroid Build Coastguard Worker# Note that setting LD_LIBRARY_PATH with os.putenv() sometimes doesn't help.
31*8d67ca89SAndroid Build Coastguard Workerclang.cindex.Config.set_library_file(os.path.join(top, 'prebuilts/clang/host/linux-x86/clang-stable/lib/libclang.so'))
32*8d67ca89SAndroid Build Coastguard Worker
33*8d67ca89SAndroid Build Coastguard Workerfrom defaults import *
34*8d67ca89SAndroid Build Coastguard Worker
35*8d67ca89SAndroid Build Coastguard Worker
36*8d67ca89SAndroid Build Coastguard WorkerdebugBlockParser = False
37*8d67ca89SAndroid Build Coastguard WorkerdebugCppExpr = False
38*8d67ca89SAndroid Build Coastguard WorkerdebugOptimIf01 = False
39*8d67ca89SAndroid Build Coastguard Worker
40*8d67ca89SAndroid Build Coastguard Worker###############################################################################
41*8d67ca89SAndroid Build Coastguard Worker###############################################################################
42*8d67ca89SAndroid Build Coastguard Worker#####                                                                     #####
43*8d67ca89SAndroid Build Coastguard Worker#####           C P P   T O K E N S                                       #####
44*8d67ca89SAndroid Build Coastguard Worker#####                                                                     #####
45*8d67ca89SAndroid Build Coastguard Worker###############################################################################
46*8d67ca89SAndroid Build Coastguard Worker###############################################################################
47*8d67ca89SAndroid Build Coastguard Worker
48*8d67ca89SAndroid Build Coastguard Worker# the list of supported C-preprocessor tokens
49*8d67ca89SAndroid Build Coastguard Worker# plus a couple of C tokens as well
50*8d67ca89SAndroid Build Coastguard WorkertokEOF = "\0"
51*8d67ca89SAndroid Build Coastguard WorkertokLN = "\n"
52*8d67ca89SAndroid Build Coastguard WorkertokSTRINGIFY = "#"
53*8d67ca89SAndroid Build Coastguard WorkertokCONCAT = "##"
54*8d67ca89SAndroid Build Coastguard WorkertokLOGICAND = "&&"
55*8d67ca89SAndroid Build Coastguard WorkertokLOGICOR = "||"
56*8d67ca89SAndroid Build Coastguard WorkertokSHL = "<<"
57*8d67ca89SAndroid Build Coastguard WorkertokSHR = ">>"
58*8d67ca89SAndroid Build Coastguard WorkertokEQUAL = "=="
59*8d67ca89SAndroid Build Coastguard WorkertokNEQUAL = "!="
60*8d67ca89SAndroid Build Coastguard WorkertokLT = "<"
61*8d67ca89SAndroid Build Coastguard WorkertokLTE = "<="
62*8d67ca89SAndroid Build Coastguard WorkertokGT = ">"
63*8d67ca89SAndroid Build Coastguard WorkertokGTE = ">="
64*8d67ca89SAndroid Build Coastguard WorkertokELLIPSIS = "..."
65*8d67ca89SAndroid Build Coastguard WorkertokSPACE = " "
66*8d67ca89SAndroid Build Coastguard WorkertokDEFINED = "defined"
67*8d67ca89SAndroid Build Coastguard WorkertokLPAREN = "("
68*8d67ca89SAndroid Build Coastguard WorkertokRPAREN = ")"
69*8d67ca89SAndroid Build Coastguard WorkertokNOT = "!"
70*8d67ca89SAndroid Build Coastguard WorkertokPLUS = "+"
71*8d67ca89SAndroid Build Coastguard WorkertokMINUS = "-"
72*8d67ca89SAndroid Build Coastguard WorkertokMULTIPLY = "*"
73*8d67ca89SAndroid Build Coastguard WorkertokDIVIDE = "/"
74*8d67ca89SAndroid Build Coastguard WorkertokMODULUS = "%"
75*8d67ca89SAndroid Build Coastguard WorkertokBINAND = "&"
76*8d67ca89SAndroid Build Coastguard WorkertokBINOR = "|"
77*8d67ca89SAndroid Build Coastguard WorkertokBINXOR = "^"
78*8d67ca89SAndroid Build Coastguard WorkertokCOMMA = ","
79*8d67ca89SAndroid Build Coastguard WorkertokLBRACE = "{"
80*8d67ca89SAndroid Build Coastguard WorkertokRBRACE = "}"
81*8d67ca89SAndroid Build Coastguard WorkertokARROW = "->"
82*8d67ca89SAndroid Build Coastguard WorkertokINCREMENT = "++"
83*8d67ca89SAndroid Build Coastguard WorkertokDECREMENT = "--"
84*8d67ca89SAndroid Build Coastguard WorkertokNUMBER = "<number>"
85*8d67ca89SAndroid Build Coastguard WorkertokIDENT = "<ident>"
86*8d67ca89SAndroid Build Coastguard WorkertokSTRING = "<string>"
87*8d67ca89SAndroid Build Coastguard Worker
88*8d67ca89SAndroid Build Coastguard Worker
89*8d67ca89SAndroid Build Coastguard Workerclass Token(clang.cindex.Token):
90*8d67ca89SAndroid Build Coastguard Worker    """A class that represents one token after parsing.
91*8d67ca89SAndroid Build Coastguard Worker
92*8d67ca89SAndroid Build Coastguard Worker    It inherits the class in libclang, with an extra id property to hold the
93*8d67ca89SAndroid Build Coastguard Worker    new spelling of the token. The spelling property in the base class is
94*8d67ca89SAndroid Build Coastguard Worker    defined as read-only. New names after macro instantiation are saved in
95*8d67ca89SAndroid Build Coastguard Worker    their ids now. It also facilitates the renaming of directive optimizations
96*8d67ca89SAndroid Build Coastguard Worker    like replacing 'ifndef X' with 'if !defined(X)'.
97*8d67ca89SAndroid Build Coastguard Worker
98*8d67ca89SAndroid Build Coastguard Worker    It also overrides the cursor property of the base class. Because the one
99*8d67ca89SAndroid Build Coastguard Worker    in libclang always queries based on a single token, which usually doesn't
100*8d67ca89SAndroid Build Coastguard Worker    hold useful information. The cursor in this class can be set by calling
101*8d67ca89SAndroid Build Coastguard Worker    CppTokenizer.getTokensWithCursors(). Otherwise it returns the one in the
102*8d67ca89SAndroid Build Coastguard Worker    base class.
103*8d67ca89SAndroid Build Coastguard Worker    """
104*8d67ca89SAndroid Build Coastguard Worker
105*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, tu=None, group=None, int_data=None, ptr_data=None,
106*8d67ca89SAndroid Build Coastguard Worker                 cursor=None):
107*8d67ca89SAndroid Build Coastguard Worker        clang.cindex.Token.__init__(self)
108*8d67ca89SAndroid Build Coastguard Worker        self._id = None
109*8d67ca89SAndroid Build Coastguard Worker        self._tu = tu
110*8d67ca89SAndroid Build Coastguard Worker        self._group = group
111*8d67ca89SAndroid Build Coastguard Worker        self._cursor = cursor
112*8d67ca89SAndroid Build Coastguard Worker        # self.int_data and self.ptr_data are from the base class. But
113*8d67ca89SAndroid Build Coastguard Worker        # self.int_data doesn't accept a None value.
114*8d67ca89SAndroid Build Coastguard Worker        if int_data is not None:
115*8d67ca89SAndroid Build Coastguard Worker            self.int_data = int_data
116*8d67ca89SAndroid Build Coastguard Worker        self.ptr_data = ptr_data
117*8d67ca89SAndroid Build Coastguard Worker
118*8d67ca89SAndroid Build Coastguard Worker    @property
119*8d67ca89SAndroid Build Coastguard Worker    def id(self):
120*8d67ca89SAndroid Build Coastguard Worker        """Name of the token."""
121*8d67ca89SAndroid Build Coastguard Worker        if self._id is None:
122*8d67ca89SAndroid Build Coastguard Worker            return self.spelling
123*8d67ca89SAndroid Build Coastguard Worker        else:
124*8d67ca89SAndroid Build Coastguard Worker            return self._id
125*8d67ca89SAndroid Build Coastguard Worker
126*8d67ca89SAndroid Build Coastguard Worker    @id.setter
127*8d67ca89SAndroid Build Coastguard Worker    def id(self, new_id):
128*8d67ca89SAndroid Build Coastguard Worker        """Setting name of the token."""
129*8d67ca89SAndroid Build Coastguard Worker        self._id = new_id
130*8d67ca89SAndroid Build Coastguard Worker
131*8d67ca89SAndroid Build Coastguard Worker    @property
132*8d67ca89SAndroid Build Coastguard Worker    def cursor(self):
133*8d67ca89SAndroid Build Coastguard Worker        if self._cursor is None:
134*8d67ca89SAndroid Build Coastguard Worker            self._cursor = clang.cindex.Token.cursor
135*8d67ca89SAndroid Build Coastguard Worker        return self._cursor
136*8d67ca89SAndroid Build Coastguard Worker
137*8d67ca89SAndroid Build Coastguard Worker    @cursor.setter
138*8d67ca89SAndroid Build Coastguard Worker    def cursor(self, new_cursor):
139*8d67ca89SAndroid Build Coastguard Worker        self._cursor = new_cursor
140*8d67ca89SAndroid Build Coastguard Worker
141*8d67ca89SAndroid Build Coastguard Worker    def __repr__(self):
142*8d67ca89SAndroid Build Coastguard Worker        if self.id == 'defined':
143*8d67ca89SAndroid Build Coastguard Worker            return self.id
144*8d67ca89SAndroid Build Coastguard Worker        elif self.kind == TokenKind.IDENTIFIER:
145*8d67ca89SAndroid Build Coastguard Worker            return "(ident %s)" % self.id
146*8d67ca89SAndroid Build Coastguard Worker
147*8d67ca89SAndroid Build Coastguard Worker        return self.id
148*8d67ca89SAndroid Build Coastguard Worker
149*8d67ca89SAndroid Build Coastguard Worker    def __str__(self):
150*8d67ca89SAndroid Build Coastguard Worker        return self.id
151*8d67ca89SAndroid Build Coastguard Worker
152*8d67ca89SAndroid Build Coastguard Worker
153*8d67ca89SAndroid Build Coastguard Workerclass BadExpectedToken(Exception):
154*8d67ca89SAndroid Build Coastguard Worker    """An exception that will be raised for unexpected tokens."""
155*8d67ca89SAndroid Build Coastguard Worker    pass
156*8d67ca89SAndroid Build Coastguard Worker
157*8d67ca89SAndroid Build Coastguard Worker
158*8d67ca89SAndroid Build Coastguard Workerclass UnparseableStruct(Exception):
159*8d67ca89SAndroid Build Coastguard Worker    """An exception that will be raised for structs that cannot be parsed."""
160*8d67ca89SAndroid Build Coastguard Worker    pass
161*8d67ca89SAndroid Build Coastguard Worker
162*8d67ca89SAndroid Build Coastguard Worker
163*8d67ca89SAndroid Build Coastguard Worker# The __contains__ function in libclang SourceRange class contains a bug. It
164*8d67ca89SAndroid Build Coastguard Worker# gives wrong result when dealing with single line range.
165*8d67ca89SAndroid Build Coastguard Worker# Bug filed with upstream:
166*8d67ca89SAndroid Build Coastguard Worker# http://llvm.org/bugs/show_bug.cgi?id=22243, http://reviews.llvm.org/D7277
167*8d67ca89SAndroid Build Coastguard Workerdef SourceRange__contains__(self, other):
168*8d67ca89SAndroid Build Coastguard Worker    """Determine if a given location is inside the range."""
169*8d67ca89SAndroid Build Coastguard Worker    if not isinstance(other, SourceLocation):
170*8d67ca89SAndroid Build Coastguard Worker        return False
171*8d67ca89SAndroid Build Coastguard Worker    if other.file is None and self.start.file is None:
172*8d67ca89SAndroid Build Coastguard Worker        pass
173*8d67ca89SAndroid Build Coastguard Worker    elif (self.start.file.name != other.file.name or
174*8d67ca89SAndroid Build Coastguard Worker          other.file.name != self.end.file.name):
175*8d67ca89SAndroid Build Coastguard Worker        # same file name
176*8d67ca89SAndroid Build Coastguard Worker        return False
177*8d67ca89SAndroid Build Coastguard Worker    # same file, in between lines
178*8d67ca89SAndroid Build Coastguard Worker    if self.start.line < other.line < self.end.line:
179*8d67ca89SAndroid Build Coastguard Worker        return True
180*8d67ca89SAndroid Build Coastguard Worker    # same file, same line
181*8d67ca89SAndroid Build Coastguard Worker    elif self.start.line == other.line == self.end.line:
182*8d67ca89SAndroid Build Coastguard Worker        if self.start.column <= other.column <= self.end.column:
183*8d67ca89SAndroid Build Coastguard Worker            return True
184*8d67ca89SAndroid Build Coastguard Worker    elif self.start.line == other.line:
185*8d67ca89SAndroid Build Coastguard Worker        # same file first line
186*8d67ca89SAndroid Build Coastguard Worker        if self.start.column <= other.column:
187*8d67ca89SAndroid Build Coastguard Worker            return True
188*8d67ca89SAndroid Build Coastguard Worker    elif other.line == self.end.line:
189*8d67ca89SAndroid Build Coastguard Worker        # same file last line
190*8d67ca89SAndroid Build Coastguard Worker        if other.column <= self.end.column:
191*8d67ca89SAndroid Build Coastguard Worker            return True
192*8d67ca89SAndroid Build Coastguard Worker    return False
193*8d67ca89SAndroid Build Coastguard Worker
194*8d67ca89SAndroid Build Coastguard Worker
195*8d67ca89SAndroid Build Coastguard WorkerSourceRange.__contains__ = SourceRange__contains__
196*8d67ca89SAndroid Build Coastguard Worker
197*8d67ca89SAndroid Build Coastguard Worker
198*8d67ca89SAndroid Build Coastguard Worker################################################################################
199*8d67ca89SAndroid Build Coastguard Worker################################################################################
200*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
201*8d67ca89SAndroid Build Coastguard Worker#####           C P P   T O K E N I Z E R                                  #####
202*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
203*8d67ca89SAndroid Build Coastguard Worker################################################################################
204*8d67ca89SAndroid Build Coastguard Worker################################################################################
205*8d67ca89SAndroid Build Coastguard Worker
206*8d67ca89SAndroid Build Coastguard Worker
207*8d67ca89SAndroid Build Coastguard Workerclass CppTokenizer(object):
208*8d67ca89SAndroid Build Coastguard Worker    """A tokenizer that converts some input text into a list of tokens.
209*8d67ca89SAndroid Build Coastguard Worker
210*8d67ca89SAndroid Build Coastguard Worker    It calls libclang's tokenizer to get the parsed tokens. In addition, it
211*8d67ca89SAndroid Build Coastguard Worker    updates the cursor property in each token after parsing, by calling
212*8d67ca89SAndroid Build Coastguard Worker    getTokensWithCursors().
213*8d67ca89SAndroid Build Coastguard Worker    """
214*8d67ca89SAndroid Build Coastguard Worker
215*8d67ca89SAndroid Build Coastguard Worker    clang_flags = ['-E', '-x', 'c']
216*8d67ca89SAndroid Build Coastguard Worker    options = TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
217*8d67ca89SAndroid Build Coastguard Worker
218*8d67ca89SAndroid Build Coastguard Worker    def __init__(self):
219*8d67ca89SAndroid Build Coastguard Worker        """Initialize a new CppTokenizer object."""
220*8d67ca89SAndroid Build Coastguard Worker        self._indexer = clang.cindex.Index.create()
221*8d67ca89SAndroid Build Coastguard Worker        self._tu = None
222*8d67ca89SAndroid Build Coastguard Worker        self._index = 0
223*8d67ca89SAndroid Build Coastguard Worker        self.tokens = None
224*8d67ca89SAndroid Build Coastguard Worker
225*8d67ca89SAndroid Build Coastguard Worker    def _getTokensWithCursors(self):
226*8d67ca89SAndroid Build Coastguard Worker        """Helper method to return all tokens with their cursors.
227*8d67ca89SAndroid Build Coastguard Worker
228*8d67ca89SAndroid Build Coastguard Worker        The cursor property in a clang Token doesn't provide enough
229*8d67ca89SAndroid Build Coastguard Worker        information. Because it is queried based on single token each time
230*8d67ca89SAndroid Build Coastguard Worker        without any context, i.e. via calling conf.lib.clang_annotateTokens()
231*8d67ca89SAndroid Build Coastguard Worker        with only one token given. So we often see 'INVALID_FILE' in one
232*8d67ca89SAndroid Build Coastguard Worker        token's cursor. In this function it passes all the available tokens
233*8d67ca89SAndroid Build Coastguard Worker        to get more informative cursors.
234*8d67ca89SAndroid Build Coastguard Worker        """
235*8d67ca89SAndroid Build Coastguard Worker
236*8d67ca89SAndroid Build Coastguard Worker        tokens_memory = ctypes.POINTER(clang.cindex.Token)()
237*8d67ca89SAndroid Build Coastguard Worker        tokens_count = ctypes.c_uint()
238*8d67ca89SAndroid Build Coastguard Worker
239*8d67ca89SAndroid Build Coastguard Worker        conf.lib.clang_tokenize(self._tu, self._tu.cursor.extent,
240*8d67ca89SAndroid Build Coastguard Worker                                ctypes.byref(tokens_memory),
241*8d67ca89SAndroid Build Coastguard Worker                                ctypes.byref(tokens_count))
242*8d67ca89SAndroid Build Coastguard Worker
243*8d67ca89SAndroid Build Coastguard Worker        count = int(tokens_count.value)
244*8d67ca89SAndroid Build Coastguard Worker
245*8d67ca89SAndroid Build Coastguard Worker        # If we get no tokens, no memory was allocated. Be sure not to return
246*8d67ca89SAndroid Build Coastguard Worker        # anything and potentially call a destructor on nothing.
247*8d67ca89SAndroid Build Coastguard Worker        if count < 1:
248*8d67ca89SAndroid Build Coastguard Worker            return
249*8d67ca89SAndroid Build Coastguard Worker
250*8d67ca89SAndroid Build Coastguard Worker        cursors = (Cursor * count)()
251*8d67ca89SAndroid Build Coastguard Worker        cursors_memory = ctypes.cast(cursors, ctypes.POINTER(Cursor))
252*8d67ca89SAndroid Build Coastguard Worker
253*8d67ca89SAndroid Build Coastguard Worker        conf.lib.clang_annotateTokens(self._tu, tokens_memory, count,
254*8d67ca89SAndroid Build Coastguard Worker                                      cursors_memory)
255*8d67ca89SAndroid Build Coastguard Worker
256*8d67ca89SAndroid Build Coastguard Worker        tokens_array = ctypes.cast(
257*8d67ca89SAndroid Build Coastguard Worker            tokens_memory,
258*8d67ca89SAndroid Build Coastguard Worker            ctypes.POINTER(clang.cindex.Token * count)).contents
259*8d67ca89SAndroid Build Coastguard Worker        token_group = TokenGroup(self._tu, tokens_memory, tokens_count)
260*8d67ca89SAndroid Build Coastguard Worker
261*8d67ca89SAndroid Build Coastguard Worker        tokens = []
262*8d67ca89SAndroid Build Coastguard Worker        for i in range(0, count):
263*8d67ca89SAndroid Build Coastguard Worker            token = Token(self._tu, token_group,
264*8d67ca89SAndroid Build Coastguard Worker                          int_data=tokens_array[i].int_data,
265*8d67ca89SAndroid Build Coastguard Worker                          ptr_data=tokens_array[i].ptr_data,
266*8d67ca89SAndroid Build Coastguard Worker                          cursor=cursors[i])
267*8d67ca89SAndroid Build Coastguard Worker            # We only want non-comment tokens.
268*8d67ca89SAndroid Build Coastguard Worker            if token.kind != TokenKind.COMMENT:
269*8d67ca89SAndroid Build Coastguard Worker                tokens.append(token)
270*8d67ca89SAndroid Build Coastguard Worker
271*8d67ca89SAndroid Build Coastguard Worker        return tokens
272*8d67ca89SAndroid Build Coastguard Worker
273*8d67ca89SAndroid Build Coastguard Worker    def parseString(self, lines):
274*8d67ca89SAndroid Build Coastguard Worker        """Parse a list of text lines into a BlockList object."""
275*8d67ca89SAndroid Build Coastguard Worker        file_ = 'no-filename-available.c'
276*8d67ca89SAndroid Build Coastguard Worker        self._tu = self._indexer.parse(file_, self.clang_flags,
277*8d67ca89SAndroid Build Coastguard Worker                                       unsaved_files=[(file_, lines)],
278*8d67ca89SAndroid Build Coastguard Worker                                       options=self.options)
279*8d67ca89SAndroid Build Coastguard Worker        self.tokens = self._getTokensWithCursors()
280*8d67ca89SAndroid Build Coastguard Worker
281*8d67ca89SAndroid Build Coastguard Worker    def parseFile(self, file_):
282*8d67ca89SAndroid Build Coastguard Worker        """Parse a file into a BlockList object."""
283*8d67ca89SAndroid Build Coastguard Worker        self._tu = self._indexer.parse(file_, self.clang_flags,
284*8d67ca89SAndroid Build Coastguard Worker                                       options=self.options)
285*8d67ca89SAndroid Build Coastguard Worker        self.tokens = self._getTokensWithCursors()
286*8d67ca89SAndroid Build Coastguard Worker
287*8d67ca89SAndroid Build Coastguard Worker    def nextToken(self):
288*8d67ca89SAndroid Build Coastguard Worker        """Return next token from the list."""
289*8d67ca89SAndroid Build Coastguard Worker        if self._index < len(self.tokens):
290*8d67ca89SAndroid Build Coastguard Worker            t = self.tokens[self._index]
291*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
292*8d67ca89SAndroid Build Coastguard Worker            return t
293*8d67ca89SAndroid Build Coastguard Worker        else:
294*8d67ca89SAndroid Build Coastguard Worker            return None
295*8d67ca89SAndroid Build Coastguard Worker
296*8d67ca89SAndroid Build Coastguard Worker
297*8d67ca89SAndroid Build Coastguard Workerclass CppStringTokenizer(CppTokenizer):
298*8d67ca89SAndroid Build Coastguard Worker    """A CppTokenizer derived class that accepts a string of text as input."""
299*8d67ca89SAndroid Build Coastguard Worker
300*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, line):
301*8d67ca89SAndroid Build Coastguard Worker        CppTokenizer.__init__(self)
302*8d67ca89SAndroid Build Coastguard Worker        self.parseString(line)
303*8d67ca89SAndroid Build Coastguard Worker
304*8d67ca89SAndroid Build Coastguard Worker
305*8d67ca89SAndroid Build Coastguard Workerclass CppFileTokenizer(CppTokenizer):
306*8d67ca89SAndroid Build Coastguard Worker    """A CppTokenizer derived class that accepts a file as input."""
307*8d67ca89SAndroid Build Coastguard Worker
308*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, file_):
309*8d67ca89SAndroid Build Coastguard Worker        CppTokenizer.__init__(self)
310*8d67ca89SAndroid Build Coastguard Worker        self.parseFile(file_)
311*8d67ca89SAndroid Build Coastguard Worker
312*8d67ca89SAndroid Build Coastguard Worker
313*8d67ca89SAndroid Build Coastguard Worker# Unit testing
314*8d67ca89SAndroid Build Coastguard Worker#
315*8d67ca89SAndroid Build Coastguard Workerclass CppTokenizerTests(unittest.TestCase):
316*8d67ca89SAndroid Build Coastguard Worker    """CppTokenizer tests."""
317*8d67ca89SAndroid Build Coastguard Worker
318*8d67ca89SAndroid Build Coastguard Worker    def get_tokens(self, token_string, line_col=False):
319*8d67ca89SAndroid Build Coastguard Worker        tokens = CppStringTokenizer(token_string)
320*8d67ca89SAndroid Build Coastguard Worker        token_list = []
321*8d67ca89SAndroid Build Coastguard Worker        while True:
322*8d67ca89SAndroid Build Coastguard Worker            token = tokens.nextToken()
323*8d67ca89SAndroid Build Coastguard Worker            if not token:
324*8d67ca89SAndroid Build Coastguard Worker                break
325*8d67ca89SAndroid Build Coastguard Worker            if line_col:
326*8d67ca89SAndroid Build Coastguard Worker                token_list.append((token.id, token.location.line,
327*8d67ca89SAndroid Build Coastguard Worker                                   token.location.column))
328*8d67ca89SAndroid Build Coastguard Worker            else:
329*8d67ca89SAndroid Build Coastguard Worker                token_list.append(token.id)
330*8d67ca89SAndroid Build Coastguard Worker        return token_list
331*8d67ca89SAndroid Build Coastguard Worker
332*8d67ca89SAndroid Build Coastguard Worker    def test_hash(self):
333*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("#an/example  && (01923_xy)"),
334*8d67ca89SAndroid Build Coastguard Worker                         ["#", "an", "/", "example", tokLOGICAND, tokLPAREN,
335*8d67ca89SAndroid Build Coastguard Worker                          "01923_xy", tokRPAREN])
336*8d67ca89SAndroid Build Coastguard Worker
337*8d67ca89SAndroid Build Coastguard Worker    def test_parens(self):
338*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("FOO(BAR) && defined(BAZ)"),
339*8d67ca89SAndroid Build Coastguard Worker                         ["FOO", tokLPAREN, "BAR", tokRPAREN, tokLOGICAND,
340*8d67ca89SAndroid Build Coastguard Worker                          "defined", tokLPAREN, "BAZ", tokRPAREN])
341*8d67ca89SAndroid Build Coastguard Worker
342*8d67ca89SAndroid Build Coastguard Worker    def test_comment(self):
343*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("/*\n#\n*/"), [])
344*8d67ca89SAndroid Build Coastguard Worker
345*8d67ca89SAndroid Build Coastguard Worker    def test_line_cross(self):
346*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("first\nsecond"), ["first", "second"])
347*8d67ca89SAndroid Build Coastguard Worker
348*8d67ca89SAndroid Build Coastguard Worker    def test_line_cross_line_col(self):
349*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("first second\n  third", True),
350*8d67ca89SAndroid Build Coastguard Worker                         [("first", 1, 1), ("second", 1, 7), ("third", 2, 3)])
351*8d67ca89SAndroid Build Coastguard Worker
352*8d67ca89SAndroid Build Coastguard Worker    def test_comment_line_col(self):
353*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("boo /* what the\nhell */", True),
354*8d67ca89SAndroid Build Coastguard Worker                         [("boo", 1, 1)])
355*8d67ca89SAndroid Build Coastguard Worker
356*8d67ca89SAndroid Build Coastguard Worker    def test_escapes(self):
357*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_tokens("an \\\n example", True),
358*8d67ca89SAndroid Build Coastguard Worker                         [("an", 1, 1), ("example", 2, 2)])
359*8d67ca89SAndroid Build Coastguard Worker
360*8d67ca89SAndroid Build Coastguard Worker
361*8d67ca89SAndroid Build Coastguard Worker################################################################################
362*8d67ca89SAndroid Build Coastguard Worker################################################################################
363*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
364*8d67ca89SAndroid Build Coastguard Worker#####           C P P   E X P R E S S I O N S                              #####
365*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
366*8d67ca89SAndroid Build Coastguard Worker################################################################################
367*8d67ca89SAndroid Build Coastguard Worker################################################################################
368*8d67ca89SAndroid Build Coastguard Worker
369*8d67ca89SAndroid Build Coastguard Worker
370*8d67ca89SAndroid Build Coastguard Workerclass CppExpr(object):
371*8d67ca89SAndroid Build Coastguard Worker    """A class that models the condition of #if directives into an expr tree.
372*8d67ca89SAndroid Build Coastguard Worker
373*8d67ca89SAndroid Build Coastguard Worker    Each node in the tree is of the form (op, arg) or (op, arg1, arg2) where
374*8d67ca89SAndroid Build Coastguard Worker    "op" is a string describing the operation
375*8d67ca89SAndroid Build Coastguard Worker    """
376*8d67ca89SAndroid Build Coastguard Worker
377*8d67ca89SAndroid Build Coastguard Worker    unaries = ["!", "~"]
378*8d67ca89SAndroid Build Coastguard Worker    binaries = ["+", "-", "<", "<=", ">=", ">", "&&", "||", "*", "/", "%",
379*8d67ca89SAndroid Build Coastguard Worker                "&", "|", "^", "<<", ">>", "==", "!=", "?", ":"]
380*8d67ca89SAndroid Build Coastguard Worker    precedences = {
381*8d67ca89SAndroid Build Coastguard Worker        "?": 1, ":": 1,
382*8d67ca89SAndroid Build Coastguard Worker        "||": 2,
383*8d67ca89SAndroid Build Coastguard Worker        "&&": 3,
384*8d67ca89SAndroid Build Coastguard Worker        "|": 4,
385*8d67ca89SAndroid Build Coastguard Worker        "^": 5,
386*8d67ca89SAndroid Build Coastguard Worker        "&": 6,
387*8d67ca89SAndroid Build Coastguard Worker        "==": 7, "!=": 7,
388*8d67ca89SAndroid Build Coastguard Worker        "<": 8, "<=": 8, ">": 8, ">=": 8,
389*8d67ca89SAndroid Build Coastguard Worker        "<<": 9, ">>": 9,
390*8d67ca89SAndroid Build Coastguard Worker        "+": 10, "-": 10,
391*8d67ca89SAndroid Build Coastguard Worker        "*": 11, "/": 11, "%": 11,
392*8d67ca89SAndroid Build Coastguard Worker        "!": 12, "~": 12
393*8d67ca89SAndroid Build Coastguard Worker    }
394*8d67ca89SAndroid Build Coastguard Worker
395*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, tokens):
396*8d67ca89SAndroid Build Coastguard Worker        """Initialize a CppExpr. 'tokens' must be a CppToken list."""
397*8d67ca89SAndroid Build Coastguard Worker        self.tokens = tokens
398*8d67ca89SAndroid Build Coastguard Worker        self._num_tokens = len(tokens)
399*8d67ca89SAndroid Build Coastguard Worker        self._index = 0
400*8d67ca89SAndroid Build Coastguard Worker
401*8d67ca89SAndroid Build Coastguard Worker        if debugCppExpr:
402*8d67ca89SAndroid Build Coastguard Worker            print("CppExpr: trying to parse %s" % repr(tokens))
403*8d67ca89SAndroid Build Coastguard Worker        self.expr = self.parseExpression(0)
404*8d67ca89SAndroid Build Coastguard Worker        if debugCppExpr:
405*8d67ca89SAndroid Build Coastguard Worker            print("CppExpr: got " + repr(self.expr))
406*8d67ca89SAndroid Build Coastguard Worker        if self._index != self._num_tokens:
407*8d67ca89SAndroid Build Coastguard Worker            self.throw(BadExpectedToken, "crap at end of input (%d != %d): %s"
408*8d67ca89SAndroid Build Coastguard Worker                       % (self._index, self._num_tokens, repr(tokens)))
409*8d67ca89SAndroid Build Coastguard Worker
410*8d67ca89SAndroid Build Coastguard Worker    def throw(self, exception, msg):
411*8d67ca89SAndroid Build Coastguard Worker        if self._index < self._num_tokens:
412*8d67ca89SAndroid Build Coastguard Worker            tok = self.tokens[self._index]
413*8d67ca89SAndroid Build Coastguard Worker            print("%d:%d: %s" % (tok.location.line, tok.location.column, msg))
414*8d67ca89SAndroid Build Coastguard Worker        else:
415*8d67ca89SAndroid Build Coastguard Worker            print("EOF: %s" % msg)
416*8d67ca89SAndroid Build Coastguard Worker        raise exception(msg)
417*8d67ca89SAndroid Build Coastguard Worker
418*8d67ca89SAndroid Build Coastguard Worker    def expectId(self, id):
419*8d67ca89SAndroid Build Coastguard Worker        """Check that a given token id is at the current position."""
420*8d67ca89SAndroid Build Coastguard Worker        token = self.tokens[self._index]
421*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens or token.id != id:
422*8d67ca89SAndroid Build Coastguard Worker            self.throw(BadExpectedToken,
423*8d67ca89SAndroid Build Coastguard Worker                       "### expecting '%s' in expression, got '%s'" % (
424*8d67ca89SAndroid Build Coastguard Worker                           id, token.id))
425*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
426*8d67ca89SAndroid Build Coastguard Worker
427*8d67ca89SAndroid Build Coastguard Worker    def is_decimal(self):
428*8d67ca89SAndroid Build Coastguard Worker        token = self.tokens[self._index].id
429*8d67ca89SAndroid Build Coastguard Worker        if token[-1] in "ULul":
430*8d67ca89SAndroid Build Coastguard Worker            token = token[:-1]
431*8d67ca89SAndroid Build Coastguard Worker        try:
432*8d67ca89SAndroid Build Coastguard Worker            val = int(token, 10)
433*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
434*8d67ca89SAndroid Build Coastguard Worker            return ('int', val)
435*8d67ca89SAndroid Build Coastguard Worker        except ValueError:
436*8d67ca89SAndroid Build Coastguard Worker            return None
437*8d67ca89SAndroid Build Coastguard Worker
438*8d67ca89SAndroid Build Coastguard Worker    def is_octal(self):
439*8d67ca89SAndroid Build Coastguard Worker        token = self.tokens[self._index].id
440*8d67ca89SAndroid Build Coastguard Worker        if token[-1] in "ULul":
441*8d67ca89SAndroid Build Coastguard Worker            token = token[:-1]
442*8d67ca89SAndroid Build Coastguard Worker        if len(token) < 2 or token[0] != '0':
443*8d67ca89SAndroid Build Coastguard Worker            return None
444*8d67ca89SAndroid Build Coastguard Worker        try:
445*8d67ca89SAndroid Build Coastguard Worker            val = int(token, 8)
446*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
447*8d67ca89SAndroid Build Coastguard Worker            return ('oct', val)
448*8d67ca89SAndroid Build Coastguard Worker        except ValueError:
449*8d67ca89SAndroid Build Coastguard Worker            return None
450*8d67ca89SAndroid Build Coastguard Worker
451*8d67ca89SAndroid Build Coastguard Worker    def is_hexadecimal(self):
452*8d67ca89SAndroid Build Coastguard Worker        token = self.tokens[self._index].id
453*8d67ca89SAndroid Build Coastguard Worker        if token[-1] in "ULul":
454*8d67ca89SAndroid Build Coastguard Worker            token = token[:-1]
455*8d67ca89SAndroid Build Coastguard Worker        if len(token) < 3 or (token[:2] != '0x' and token[:2] != '0X'):
456*8d67ca89SAndroid Build Coastguard Worker            return None
457*8d67ca89SAndroid Build Coastguard Worker        try:
458*8d67ca89SAndroid Build Coastguard Worker            val = int(token, 16)
459*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
460*8d67ca89SAndroid Build Coastguard Worker            return ('hex', val)
461*8d67ca89SAndroid Build Coastguard Worker        except ValueError:
462*8d67ca89SAndroid Build Coastguard Worker            return None
463*8d67ca89SAndroid Build Coastguard Worker
464*8d67ca89SAndroid Build Coastguard Worker    def is_integer(self):
465*8d67ca89SAndroid Build Coastguard Worker        if self.tokens[self._index].kind != TokenKind.LITERAL:
466*8d67ca89SAndroid Build Coastguard Worker            return None
467*8d67ca89SAndroid Build Coastguard Worker
468*8d67ca89SAndroid Build Coastguard Worker        c = self.is_hexadecimal()
469*8d67ca89SAndroid Build Coastguard Worker        if c:
470*8d67ca89SAndroid Build Coastguard Worker            return c
471*8d67ca89SAndroid Build Coastguard Worker
472*8d67ca89SAndroid Build Coastguard Worker        c = self.is_octal()
473*8d67ca89SAndroid Build Coastguard Worker        if c:
474*8d67ca89SAndroid Build Coastguard Worker            return c
475*8d67ca89SAndroid Build Coastguard Worker
476*8d67ca89SAndroid Build Coastguard Worker        c = self.is_decimal()
477*8d67ca89SAndroid Build Coastguard Worker        if c:
478*8d67ca89SAndroid Build Coastguard Worker            return c
479*8d67ca89SAndroid Build Coastguard Worker
480*8d67ca89SAndroid Build Coastguard Worker        return None
481*8d67ca89SAndroid Build Coastguard Worker
482*8d67ca89SAndroid Build Coastguard Worker    def is_number(self):
483*8d67ca89SAndroid Build Coastguard Worker        t = self.tokens[self._index]
484*8d67ca89SAndroid Build Coastguard Worker        if t.id == tokMINUS and self._index + 1 < self._num_tokens:
485*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
486*8d67ca89SAndroid Build Coastguard Worker            c = self.is_integer()
487*8d67ca89SAndroid Build Coastguard Worker            if c:
488*8d67ca89SAndroid Build Coastguard Worker                op, val = c
489*8d67ca89SAndroid Build Coastguard Worker                return (op, -val)
490*8d67ca89SAndroid Build Coastguard Worker        if t.id == tokPLUS and self._index + 1 < self._num_tokens:
491*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
492*8d67ca89SAndroid Build Coastguard Worker            c = self.is_integer()
493*8d67ca89SAndroid Build Coastguard Worker            if c:
494*8d67ca89SAndroid Build Coastguard Worker                return c
495*8d67ca89SAndroid Build Coastguard Worker
496*8d67ca89SAndroid Build Coastguard Worker        return self.is_integer()
497*8d67ca89SAndroid Build Coastguard Worker
498*8d67ca89SAndroid Build Coastguard Worker    def is_defined(self):
499*8d67ca89SAndroid Build Coastguard Worker        t = self.tokens[self._index]
500*8d67ca89SAndroid Build Coastguard Worker        if t.id != tokDEFINED:
501*8d67ca89SAndroid Build Coastguard Worker            return None
502*8d67ca89SAndroid Build Coastguard Worker
503*8d67ca89SAndroid Build Coastguard Worker        # We have the defined keyword, check the rest.
504*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
505*8d67ca89SAndroid Build Coastguard Worker        used_parens = False
506*8d67ca89SAndroid Build Coastguard Worker        if (self._index < self._num_tokens and
507*8d67ca89SAndroid Build Coastguard Worker            self.tokens[self._index].id == tokLPAREN):
508*8d67ca89SAndroid Build Coastguard Worker            used_parens = True
509*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
510*8d67ca89SAndroid Build Coastguard Worker
511*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens:
512*8d67ca89SAndroid Build Coastguard Worker            self.throw(BadExpectedToken,
513*8d67ca89SAndroid Build Coastguard Worker                       "### 'defined' must be followed by macro name or left "
514*8d67ca89SAndroid Build Coastguard Worker                       "paren")
515*8d67ca89SAndroid Build Coastguard Worker
516*8d67ca89SAndroid Build Coastguard Worker        t = self.tokens[self._index]
517*8d67ca89SAndroid Build Coastguard Worker        if t.kind != TokenKind.IDENTIFIER:
518*8d67ca89SAndroid Build Coastguard Worker            self.throw(BadExpectedToken,
519*8d67ca89SAndroid Build Coastguard Worker                       "### 'defined' must be followed by macro name")
520*8d67ca89SAndroid Build Coastguard Worker
521*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
522*8d67ca89SAndroid Build Coastguard Worker        if used_parens:
523*8d67ca89SAndroid Build Coastguard Worker            self.expectId(tokRPAREN)
524*8d67ca89SAndroid Build Coastguard Worker
525*8d67ca89SAndroid Build Coastguard Worker        return ("defined", t.id)
526*8d67ca89SAndroid Build Coastguard Worker
527*8d67ca89SAndroid Build Coastguard Worker    def is_call_or_ident(self):
528*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens:
529*8d67ca89SAndroid Build Coastguard Worker            return None
530*8d67ca89SAndroid Build Coastguard Worker
531*8d67ca89SAndroid Build Coastguard Worker        t = self.tokens[self._index]
532*8d67ca89SAndroid Build Coastguard Worker        if t.kind != TokenKind.IDENTIFIER:
533*8d67ca89SAndroid Build Coastguard Worker            return None
534*8d67ca89SAndroid Build Coastguard Worker
535*8d67ca89SAndroid Build Coastguard Worker        name = t.id
536*8d67ca89SAndroid Build Coastguard Worker
537*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
538*8d67ca89SAndroid Build Coastguard Worker        if (self._index >= self._num_tokens or
539*8d67ca89SAndroid Build Coastguard Worker            self.tokens[self._index].id != tokLPAREN):
540*8d67ca89SAndroid Build Coastguard Worker            return ("ident", name)
541*8d67ca89SAndroid Build Coastguard Worker
542*8d67ca89SAndroid Build Coastguard Worker        params = []
543*8d67ca89SAndroid Build Coastguard Worker        depth = 1
544*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
545*8d67ca89SAndroid Build Coastguard Worker        j = self._index
546*8d67ca89SAndroid Build Coastguard Worker        while self._index < self._num_tokens:
547*8d67ca89SAndroid Build Coastguard Worker            id = self.tokens[self._index].id
548*8d67ca89SAndroid Build Coastguard Worker            if id == tokLPAREN:
549*8d67ca89SAndroid Build Coastguard Worker                depth += 1
550*8d67ca89SAndroid Build Coastguard Worker            elif depth == 1 and (id == tokCOMMA or id == tokRPAREN):
551*8d67ca89SAndroid Build Coastguard Worker                k = self._index
552*8d67ca89SAndroid Build Coastguard Worker                param = self.tokens[j:k]
553*8d67ca89SAndroid Build Coastguard Worker                params.append(param)
554*8d67ca89SAndroid Build Coastguard Worker                if id == tokRPAREN:
555*8d67ca89SAndroid Build Coastguard Worker                    break
556*8d67ca89SAndroid Build Coastguard Worker                j = self._index + 1
557*8d67ca89SAndroid Build Coastguard Worker            elif id == tokRPAREN:
558*8d67ca89SAndroid Build Coastguard Worker                depth -= 1
559*8d67ca89SAndroid Build Coastguard Worker            self._index += 1
560*8d67ca89SAndroid Build Coastguard Worker
561*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens:
562*8d67ca89SAndroid Build Coastguard Worker            return None
563*8d67ca89SAndroid Build Coastguard Worker
564*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
565*8d67ca89SAndroid Build Coastguard Worker        return ("call", (name, params))
566*8d67ca89SAndroid Build Coastguard Worker
567*8d67ca89SAndroid Build Coastguard Worker    # Implements the "precedence climbing" algorithm from
568*8d67ca89SAndroid Build Coastguard Worker    # http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm.
569*8d67ca89SAndroid Build Coastguard Worker    # The "classic" algorithm would be fine if we were using a tool to
570*8d67ca89SAndroid Build Coastguard Worker    # generate the parser, but we're not. Dijkstra's "shunting yard"
571*8d67ca89SAndroid Build Coastguard Worker    # algorithm hasn't been necessary yet.
572*8d67ca89SAndroid Build Coastguard Worker
573*8d67ca89SAndroid Build Coastguard Worker    def parseExpression(self, minPrecedence):
574*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens:
575*8d67ca89SAndroid Build Coastguard Worker            return None
576*8d67ca89SAndroid Build Coastguard Worker
577*8d67ca89SAndroid Build Coastguard Worker        node = self.parsePrimary()
578*8d67ca89SAndroid Build Coastguard Worker        while (self.token() and self.isBinary(self.token()) and
579*8d67ca89SAndroid Build Coastguard Worker               self.precedence(self.token()) >= minPrecedence):
580*8d67ca89SAndroid Build Coastguard Worker            op = self.token()
581*8d67ca89SAndroid Build Coastguard Worker            self.nextToken()
582*8d67ca89SAndroid Build Coastguard Worker            rhs = self.parseExpression(self.precedence(op) + 1)
583*8d67ca89SAndroid Build Coastguard Worker            node = (op.id, node, rhs)
584*8d67ca89SAndroid Build Coastguard Worker
585*8d67ca89SAndroid Build Coastguard Worker        return node
586*8d67ca89SAndroid Build Coastguard Worker
587*8d67ca89SAndroid Build Coastguard Worker    def parsePrimary(self):
588*8d67ca89SAndroid Build Coastguard Worker        op = self.token()
589*8d67ca89SAndroid Build Coastguard Worker        if self.isUnary(op):
590*8d67ca89SAndroid Build Coastguard Worker            self.nextToken()
591*8d67ca89SAndroid Build Coastguard Worker            return (op.id, self.parseExpression(self.precedence(op)))
592*8d67ca89SAndroid Build Coastguard Worker
593*8d67ca89SAndroid Build Coastguard Worker        primary = None
594*8d67ca89SAndroid Build Coastguard Worker        if op.id == tokLPAREN:
595*8d67ca89SAndroid Build Coastguard Worker            self.nextToken()
596*8d67ca89SAndroid Build Coastguard Worker            primary = self.parseExpression(0)
597*8d67ca89SAndroid Build Coastguard Worker            self.expectId(tokRPAREN)
598*8d67ca89SAndroid Build Coastguard Worker        elif op.id == "?":
599*8d67ca89SAndroid Build Coastguard Worker            self.nextToken()
600*8d67ca89SAndroid Build Coastguard Worker            primary = self.parseExpression(0)
601*8d67ca89SAndroid Build Coastguard Worker            self.expectId(":")
602*8d67ca89SAndroid Build Coastguard Worker        elif op.id == '+' or op.id == '-' or op.kind == TokenKind.LITERAL:
603*8d67ca89SAndroid Build Coastguard Worker            primary = self.is_number()
604*8d67ca89SAndroid Build Coastguard Worker        # Checking for 'defined' needs to come first now because 'defined' is
605*8d67ca89SAndroid Build Coastguard Worker        # recognized as IDENTIFIER.
606*8d67ca89SAndroid Build Coastguard Worker        elif op.id == tokDEFINED:
607*8d67ca89SAndroid Build Coastguard Worker            primary = self.is_defined()
608*8d67ca89SAndroid Build Coastguard Worker        elif op.kind == TokenKind.IDENTIFIER:
609*8d67ca89SAndroid Build Coastguard Worker            primary = self.is_call_or_ident()
610*8d67ca89SAndroid Build Coastguard Worker        else:
611*8d67ca89SAndroid Build Coastguard Worker            self.throw(BadExpectedToken,
612*8d67ca89SAndroid Build Coastguard Worker                       "didn't expect to see a %s in factor" % (
613*8d67ca89SAndroid Build Coastguard Worker                           self.tokens[self._index].id))
614*8d67ca89SAndroid Build Coastguard Worker        return primary
615*8d67ca89SAndroid Build Coastguard Worker
616*8d67ca89SAndroid Build Coastguard Worker    def isBinary(self, token):
617*8d67ca89SAndroid Build Coastguard Worker        return token.id in self.binaries
618*8d67ca89SAndroid Build Coastguard Worker
619*8d67ca89SAndroid Build Coastguard Worker    def isUnary(self, token):
620*8d67ca89SAndroid Build Coastguard Worker        return token.id in self.unaries
621*8d67ca89SAndroid Build Coastguard Worker
622*8d67ca89SAndroid Build Coastguard Worker    def precedence(self, token):
623*8d67ca89SAndroid Build Coastguard Worker        return self.precedences.get(token.id)
624*8d67ca89SAndroid Build Coastguard Worker
625*8d67ca89SAndroid Build Coastguard Worker    def token(self):
626*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens:
627*8d67ca89SAndroid Build Coastguard Worker            return None
628*8d67ca89SAndroid Build Coastguard Worker        return self.tokens[self._index]
629*8d67ca89SAndroid Build Coastguard Worker
630*8d67ca89SAndroid Build Coastguard Worker    def nextToken(self):
631*8d67ca89SAndroid Build Coastguard Worker        self._index += 1
632*8d67ca89SAndroid Build Coastguard Worker        if self._index >= self._num_tokens:
633*8d67ca89SAndroid Build Coastguard Worker            return None
634*8d67ca89SAndroid Build Coastguard Worker        return self.tokens[self._index]
635*8d67ca89SAndroid Build Coastguard Worker
636*8d67ca89SAndroid Build Coastguard Worker    def dump_node(self, e):
637*8d67ca89SAndroid Build Coastguard Worker        op = e[0]
638*8d67ca89SAndroid Build Coastguard Worker        line = "(" + op
639*8d67ca89SAndroid Build Coastguard Worker        if op == "int":
640*8d67ca89SAndroid Build Coastguard Worker            line += " %d)" % e[1]
641*8d67ca89SAndroid Build Coastguard Worker        elif op == "oct":
642*8d67ca89SAndroid Build Coastguard Worker            line += " 0%o)" % e[1]
643*8d67ca89SAndroid Build Coastguard Worker        elif op == "hex":
644*8d67ca89SAndroid Build Coastguard Worker            line += " 0x%x)" % e[1]
645*8d67ca89SAndroid Build Coastguard Worker        elif op == "ident":
646*8d67ca89SAndroid Build Coastguard Worker            line += " %s)" % e[1]
647*8d67ca89SAndroid Build Coastguard Worker        elif op == "defined":
648*8d67ca89SAndroid Build Coastguard Worker            line += " %s)" % e[1]
649*8d67ca89SAndroid Build Coastguard Worker        elif op == "call":
650*8d67ca89SAndroid Build Coastguard Worker            arg = e[1]
651*8d67ca89SAndroid Build Coastguard Worker            line += " %s [" % arg[0]
652*8d67ca89SAndroid Build Coastguard Worker            prefix = ""
653*8d67ca89SAndroid Build Coastguard Worker            for param in arg[1]:
654*8d67ca89SAndroid Build Coastguard Worker                par = ""
655*8d67ca89SAndroid Build Coastguard Worker                for tok in param:
656*8d67ca89SAndroid Build Coastguard Worker                    par += str(tok)
657*8d67ca89SAndroid Build Coastguard Worker                line += "%s%s" % (prefix, par)
658*8d67ca89SAndroid Build Coastguard Worker                prefix = ","
659*8d67ca89SAndroid Build Coastguard Worker            line += "])"
660*8d67ca89SAndroid Build Coastguard Worker        elif op in CppExpr.unaries:
661*8d67ca89SAndroid Build Coastguard Worker            line += " %s)" % self.dump_node(e[1])
662*8d67ca89SAndroid Build Coastguard Worker        elif op in CppExpr.binaries:
663*8d67ca89SAndroid Build Coastguard Worker            line += " %s %s)" % (self.dump_node(e[1]), self.dump_node(e[2]))
664*8d67ca89SAndroid Build Coastguard Worker        else:
665*8d67ca89SAndroid Build Coastguard Worker            line += " ?%s)" % repr(e[1])
666*8d67ca89SAndroid Build Coastguard Worker
667*8d67ca89SAndroid Build Coastguard Worker        return line
668*8d67ca89SAndroid Build Coastguard Worker
669*8d67ca89SAndroid Build Coastguard Worker    def __repr__(self):
670*8d67ca89SAndroid Build Coastguard Worker        return self.dump_node(self.expr)
671*8d67ca89SAndroid Build Coastguard Worker
672*8d67ca89SAndroid Build Coastguard Worker    def source_node(self, e):
673*8d67ca89SAndroid Build Coastguard Worker        op = e[0]
674*8d67ca89SAndroid Build Coastguard Worker        if op == "int":
675*8d67ca89SAndroid Build Coastguard Worker            return "%d" % e[1]
676*8d67ca89SAndroid Build Coastguard Worker        if op == "hex":
677*8d67ca89SAndroid Build Coastguard Worker            return "0x%x" % e[1]
678*8d67ca89SAndroid Build Coastguard Worker        if op == "oct":
679*8d67ca89SAndroid Build Coastguard Worker            return "0%o" % e[1]
680*8d67ca89SAndroid Build Coastguard Worker        if op == "ident":
681*8d67ca89SAndroid Build Coastguard Worker            # XXX: should try to expand
682*8d67ca89SAndroid Build Coastguard Worker            return e[1]
683*8d67ca89SAndroid Build Coastguard Worker        if op == "defined":
684*8d67ca89SAndroid Build Coastguard Worker            return "defined(%s)" % e[1]
685*8d67ca89SAndroid Build Coastguard Worker
686*8d67ca89SAndroid Build Coastguard Worker        prec = CppExpr.precedences.get(op, 1000)
687*8d67ca89SAndroid Build Coastguard Worker        arg = e[1]
688*8d67ca89SAndroid Build Coastguard Worker        if op in CppExpr.unaries:
689*8d67ca89SAndroid Build Coastguard Worker            arg_src = self.source_node(arg)
690*8d67ca89SAndroid Build Coastguard Worker            arg_op = arg[0]
691*8d67ca89SAndroid Build Coastguard Worker            arg_prec = CppExpr.precedences.get(arg_op, 1000)
692*8d67ca89SAndroid Build Coastguard Worker            if arg_prec < prec:
693*8d67ca89SAndroid Build Coastguard Worker                return "!(" + arg_src + ")"
694*8d67ca89SAndroid Build Coastguard Worker            else:
695*8d67ca89SAndroid Build Coastguard Worker                return "!" + arg_src
696*8d67ca89SAndroid Build Coastguard Worker        if op in CppExpr.binaries:
697*8d67ca89SAndroid Build Coastguard Worker            arg2 = e[2]
698*8d67ca89SAndroid Build Coastguard Worker            arg1_op = arg[0]
699*8d67ca89SAndroid Build Coastguard Worker            arg2_op = arg2[0]
700*8d67ca89SAndroid Build Coastguard Worker            arg1_src = self.source_node(arg)
701*8d67ca89SAndroid Build Coastguard Worker            arg2_src = self.source_node(arg2)
702*8d67ca89SAndroid Build Coastguard Worker            if CppExpr.precedences.get(arg1_op, 1000) < prec:
703*8d67ca89SAndroid Build Coastguard Worker                arg1_src = "(%s)" % arg1_src
704*8d67ca89SAndroid Build Coastguard Worker            if CppExpr.precedences.get(arg2_op, 1000) < prec:
705*8d67ca89SAndroid Build Coastguard Worker                arg2_src = "(%s)" % arg2_src
706*8d67ca89SAndroid Build Coastguard Worker
707*8d67ca89SAndroid Build Coastguard Worker            return "%s %s %s" % (arg1_src, op, arg2_src)
708*8d67ca89SAndroid Build Coastguard Worker        return "???"
709*8d67ca89SAndroid Build Coastguard Worker
710*8d67ca89SAndroid Build Coastguard Worker    def __str__(self):
711*8d67ca89SAndroid Build Coastguard Worker        return self.source_node(self.expr)
712*8d67ca89SAndroid Build Coastguard Worker
713*8d67ca89SAndroid Build Coastguard Worker    @staticmethod
714*8d67ca89SAndroid Build Coastguard Worker    def int_node(e):
715*8d67ca89SAndroid Build Coastguard Worker        if e[0] in ["int", "oct", "hex"]:
716*8d67ca89SAndroid Build Coastguard Worker            return e[1]
717*8d67ca89SAndroid Build Coastguard Worker        else:
718*8d67ca89SAndroid Build Coastguard Worker            return None
719*8d67ca89SAndroid Build Coastguard Worker
720*8d67ca89SAndroid Build Coastguard Worker    def toInt(self):
721*8d67ca89SAndroid Build Coastguard Worker        return self.int_node(self.expr)
722*8d67ca89SAndroid Build Coastguard Worker
723*8d67ca89SAndroid Build Coastguard Worker    def optimize_node(self, e, macros=None):
724*8d67ca89SAndroid Build Coastguard Worker        if macros is None:
725*8d67ca89SAndroid Build Coastguard Worker            macros = {}
726*8d67ca89SAndroid Build Coastguard Worker        op = e[0]
727*8d67ca89SAndroid Build Coastguard Worker
728*8d67ca89SAndroid Build Coastguard Worker        if op == "defined":
729*8d67ca89SAndroid Build Coastguard Worker            op, name = e
730*8d67ca89SAndroid Build Coastguard Worker            if name in macros:
731*8d67ca89SAndroid Build Coastguard Worker                if macros[name] == kCppUndefinedMacro:
732*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 0)
733*8d67ca89SAndroid Build Coastguard Worker                else:
734*8d67ca89SAndroid Build Coastguard Worker                    try:
735*8d67ca89SAndroid Build Coastguard Worker                        value = int(macros[name])
736*8d67ca89SAndroid Build Coastguard Worker                        return ("int", value)
737*8d67ca89SAndroid Build Coastguard Worker                    except ValueError:
738*8d67ca89SAndroid Build Coastguard Worker                        return ("defined", macros[name])
739*8d67ca89SAndroid Build Coastguard Worker
740*8d67ca89SAndroid Build Coastguard Worker            if kernel_remove_config_macros and name.startswith("CONFIG_"):
741*8d67ca89SAndroid Build Coastguard Worker                return ("int", 0)
742*8d67ca89SAndroid Build Coastguard Worker
743*8d67ca89SAndroid Build Coastguard Worker            return e
744*8d67ca89SAndroid Build Coastguard Worker
745*8d67ca89SAndroid Build Coastguard Worker        elif op == "ident":
746*8d67ca89SAndroid Build Coastguard Worker            op, name = e
747*8d67ca89SAndroid Build Coastguard Worker            if name in macros:
748*8d67ca89SAndroid Build Coastguard Worker                try:
749*8d67ca89SAndroid Build Coastguard Worker                    value = int(macros[name])
750*8d67ca89SAndroid Build Coastguard Worker                    expanded = ("int", value)
751*8d67ca89SAndroid Build Coastguard Worker                except ValueError:
752*8d67ca89SAndroid Build Coastguard Worker                    expanded = ("ident", macros[name])
753*8d67ca89SAndroid Build Coastguard Worker                return self.optimize_node(expanded, macros)
754*8d67ca89SAndroid Build Coastguard Worker            return e
755*8d67ca89SAndroid Build Coastguard Worker
756*8d67ca89SAndroid Build Coastguard Worker        elif op == "!":
757*8d67ca89SAndroid Build Coastguard Worker            op, v = e
758*8d67ca89SAndroid Build Coastguard Worker            v = self.optimize_node(v, macros)
759*8d67ca89SAndroid Build Coastguard Worker            if v[0] == "int":
760*8d67ca89SAndroid Build Coastguard Worker                if v[1] == 0:
761*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 1)
762*8d67ca89SAndroid Build Coastguard Worker                else:
763*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 0)
764*8d67ca89SAndroid Build Coastguard Worker            return ('!', v)
765*8d67ca89SAndroid Build Coastguard Worker
766*8d67ca89SAndroid Build Coastguard Worker        elif op == "&&":
767*8d67ca89SAndroid Build Coastguard Worker            op, l, r = e
768*8d67ca89SAndroid Build Coastguard Worker            l = self.optimize_node(l, macros)
769*8d67ca89SAndroid Build Coastguard Worker            r = self.optimize_node(r, macros)
770*8d67ca89SAndroid Build Coastguard Worker            li = self.int_node(l)
771*8d67ca89SAndroid Build Coastguard Worker            ri = self.int_node(r)
772*8d67ca89SAndroid Build Coastguard Worker            if li is not None:
773*8d67ca89SAndroid Build Coastguard Worker                if li == 0:
774*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 0)
775*8d67ca89SAndroid Build Coastguard Worker                else:
776*8d67ca89SAndroid Build Coastguard Worker                    return r
777*8d67ca89SAndroid Build Coastguard Worker            elif ri is not None:
778*8d67ca89SAndroid Build Coastguard Worker                if ri == 0:
779*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 0)
780*8d67ca89SAndroid Build Coastguard Worker                else:
781*8d67ca89SAndroid Build Coastguard Worker                    return l
782*8d67ca89SAndroid Build Coastguard Worker            return (op, l, r)
783*8d67ca89SAndroid Build Coastguard Worker
784*8d67ca89SAndroid Build Coastguard Worker        elif op == "||":
785*8d67ca89SAndroid Build Coastguard Worker            op, l, r = e
786*8d67ca89SAndroid Build Coastguard Worker            l = self.optimize_node(l, macros)
787*8d67ca89SAndroid Build Coastguard Worker            r = self.optimize_node(r, macros)
788*8d67ca89SAndroid Build Coastguard Worker            li = self.int_node(l)
789*8d67ca89SAndroid Build Coastguard Worker            ri = self.int_node(r)
790*8d67ca89SAndroid Build Coastguard Worker            if li is not None:
791*8d67ca89SAndroid Build Coastguard Worker                if li == 0:
792*8d67ca89SAndroid Build Coastguard Worker                    return r
793*8d67ca89SAndroid Build Coastguard Worker                else:
794*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 1)
795*8d67ca89SAndroid Build Coastguard Worker            elif ri is not None:
796*8d67ca89SAndroid Build Coastguard Worker                if ri == 0:
797*8d67ca89SAndroid Build Coastguard Worker                    return l
798*8d67ca89SAndroid Build Coastguard Worker                else:
799*8d67ca89SAndroid Build Coastguard Worker                    return ("int", 1)
800*8d67ca89SAndroid Build Coastguard Worker            return (op, l, r)
801*8d67ca89SAndroid Build Coastguard Worker
802*8d67ca89SAndroid Build Coastguard Worker        else:
803*8d67ca89SAndroid Build Coastguard Worker            return e
804*8d67ca89SAndroid Build Coastguard Worker
805*8d67ca89SAndroid Build Coastguard Worker    def optimize(self, macros=None):
806*8d67ca89SAndroid Build Coastguard Worker        if macros is None:
807*8d67ca89SAndroid Build Coastguard Worker            macros = {}
808*8d67ca89SAndroid Build Coastguard Worker        self.expr = self.optimize_node(self.expr, macros)
809*8d67ca89SAndroid Build Coastguard Worker
810*8d67ca89SAndroid Build Coastguard Workerclass CppExprTest(unittest.TestCase):
811*8d67ca89SAndroid Build Coastguard Worker    """CppExpr unit tests."""
812*8d67ca89SAndroid Build Coastguard Worker
813*8d67ca89SAndroid Build Coastguard Worker    def get_expr(self, expr):
814*8d67ca89SAndroid Build Coastguard Worker        return repr(CppExpr(CppStringTokenizer(expr).tokens))
815*8d67ca89SAndroid Build Coastguard Worker
816*8d67ca89SAndroid Build Coastguard Worker    def test_cpp_expr(self):
817*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("0"), "(int 0)")
818*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("1"), "(int 1)")
819*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("-5"), "(int -5)")
820*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("+1"), "(int 1)")
821*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("0U"), "(int 0)")
822*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("015"), "(oct 015)")
823*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("015l"), "(oct 015)")
824*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("0x3e"), "(hex 0x3e)")
825*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("(0)"), "(int 0)")
826*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("1 && 1"), "(&& (int 1) (int 1))")
827*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("1 && 0"), "(&& (int 1) (int 0))")
828*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("EXAMPLE"), "(ident EXAMPLE)")
829*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("EXAMPLE - 3"),
830*8d67ca89SAndroid Build Coastguard Worker                         "(- (ident EXAMPLE) (int 3))")
831*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("defined(EXAMPLE)"),
832*8d67ca89SAndroid Build Coastguard Worker                         "(defined EXAMPLE)")
833*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("defined ( EXAMPLE ) "),
834*8d67ca89SAndroid Build Coastguard Worker                         "(defined EXAMPLE)")
835*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("!defined(EXAMPLE)"),
836*8d67ca89SAndroid Build Coastguard Worker                         "(! (defined EXAMPLE))")
837*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("defined(ABC) || defined(BINGO)"),
838*8d67ca89SAndroid Build Coastguard Worker                         "(|| (defined ABC) (defined BINGO))")
839*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("FOO(BAR,5)"), "(call FOO [BAR,5])")
840*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr("A == 1 || defined(B)"),
841*8d67ca89SAndroid Build Coastguard Worker                         "(|| (== (ident A) (int 1)) (defined B))")
842*8d67ca89SAndroid Build Coastguard Worker
843*8d67ca89SAndroid Build Coastguard Worker    def get_expr_optimize(self, expr, macros=None):
844*8d67ca89SAndroid Build Coastguard Worker        if macros is None:
845*8d67ca89SAndroid Build Coastguard Worker            macros = {}
846*8d67ca89SAndroid Build Coastguard Worker        e = CppExpr(CppStringTokenizer(expr).tokens)
847*8d67ca89SAndroid Build Coastguard Worker        e.optimize(macros)
848*8d67ca89SAndroid Build Coastguard Worker        return repr(e)
849*8d67ca89SAndroid Build Coastguard Worker
850*8d67ca89SAndroid Build Coastguard Worker    def test_cpp_expr_optimize(self):
851*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("0"), "(int 0)")
852*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("1"), "(int 1)")
853*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("1 && 1"), "(int 1)")
854*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("1 && +1"), "(int 1)")
855*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("0x1 && 01"), "(oct 01)")
856*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("1 && 0"), "(int 0)")
857*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("0 && 1"), "(int 0)")
858*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("0 && 0"), "(int 0)")
859*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("1 || 1"), "(int 1)")
860*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("1 || 0"), "(int 1)")
861*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("0 || 1"), "(int 1)")
862*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("0 || 0"), "(int 0)")
863*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A"), "(ident A)")
864*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A", {"A": 1}), "(int 1)")
865*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A || B", {"A": 1}), "(int 1)")
866*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A || B", {"B": 1}), "(int 1)")
867*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A && B", {"A": 1}), "(ident B)")
868*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A && B", {"B": 1}), "(ident A)")
869*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A && B"), "(&& (ident A) (ident B))")
870*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("EXAMPLE"), "(ident EXAMPLE)")
871*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("EXAMPLE - 3"), "(- (ident EXAMPLE) (int 3))")
872*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(EXAMPLE)"), "(defined EXAMPLE)")
873*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(EXAMPLE)",
874*8d67ca89SAndroid Build Coastguard Worker                                                {"EXAMPLE": "XOWOE"}),
875*8d67ca89SAndroid Build Coastguard Worker                         "(defined XOWOE)")
876*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(EXAMPLE)",
877*8d67ca89SAndroid Build Coastguard Worker                                                {"EXAMPLE": kCppUndefinedMacro}),
878*8d67ca89SAndroid Build Coastguard Worker                         "(int 0)")
879*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("!defined(EXAMPLE)"), "(! (defined EXAMPLE))")
880*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("!defined(EXAMPLE)",
881*8d67ca89SAndroid Build Coastguard Worker                                                {"EXAMPLE": "XOWOE"}),
882*8d67ca89SAndroid Build Coastguard Worker                         "(! (defined XOWOE))")
883*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("!defined(EXAMPLE)",
884*8d67ca89SAndroid Build Coastguard Worker                                                {"EXAMPLE": kCppUndefinedMacro}),
885*8d67ca89SAndroid Build Coastguard Worker                         "(int 1)")
886*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) || defined(B)"),
887*8d67ca89SAndroid Build Coastguard Worker                        "(|| (defined A) (defined B))")
888*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) || defined(B)",
889*8d67ca89SAndroid Build Coastguard Worker                                                {"A": "1"}),
890*8d67ca89SAndroid Build Coastguard Worker                         "(int 1)")
891*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) || defined(B)",
892*8d67ca89SAndroid Build Coastguard Worker                                                {"B": "1"}),
893*8d67ca89SAndroid Build Coastguard Worker                         "(int 1)")
894*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) || defined(B)",
895*8d67ca89SAndroid Build Coastguard Worker                                                {"B": kCppUndefinedMacro}),
896*8d67ca89SAndroid Build Coastguard Worker                         "(defined A)")
897*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) || defined(B)",
898*8d67ca89SAndroid Build Coastguard Worker                                                {"A": kCppUndefinedMacro,
899*8d67ca89SAndroid Build Coastguard Worker                                                 "B": kCppUndefinedMacro}),
900*8d67ca89SAndroid Build Coastguard Worker                         "(int 0)")
901*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) && defined(B)"),
902*8d67ca89SAndroid Build Coastguard Worker                         "(&& (defined A) (defined B))")
903*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) && defined(B)",
904*8d67ca89SAndroid Build Coastguard Worker                                                {"A": "1"}),
905*8d67ca89SAndroid Build Coastguard Worker                         "(defined B)")
906*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) && defined(B)",
907*8d67ca89SAndroid Build Coastguard Worker                                                {"B": "1"}),
908*8d67ca89SAndroid Build Coastguard Worker                         "(defined A)")
909*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) && defined(B)",
910*8d67ca89SAndroid Build Coastguard Worker                                                {"B": kCppUndefinedMacro}),
911*8d67ca89SAndroid Build Coastguard Worker                        "(int 0)")
912*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("defined(A) && defined(B)",
913*8d67ca89SAndroid Build Coastguard Worker                                                {"A": kCppUndefinedMacro}),
914*8d67ca89SAndroid Build Coastguard Worker                        "(int 0)")
915*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize("A == 1 || defined(B)"),
916*8d67ca89SAndroid Build Coastguard Worker                         "(|| (== (ident A) (int 1)) (defined B))")
917*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_optimize(
918*8d67ca89SAndroid Build Coastguard Worker              "defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)",
919*8d67ca89SAndroid Build Coastguard Worker              {"__KERNEL__": kCppUndefinedMacro}),
920*8d67ca89SAndroid Build Coastguard Worker              "(|| (! (defined __GLIBC__)) (< (ident __GLIBC__) (int 2)))")
921*8d67ca89SAndroid Build Coastguard Worker
922*8d67ca89SAndroid Build Coastguard Worker    def get_expr_string(self, expr):
923*8d67ca89SAndroid Build Coastguard Worker        return str(CppExpr(CppStringTokenizer(expr).tokens))
924*8d67ca89SAndroid Build Coastguard Worker
925*8d67ca89SAndroid Build Coastguard Worker    def test_cpp_expr_string(self):
926*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("0"), "0")
927*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("1"), "1")
928*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("1 && 1"), "1 && 1")
929*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("1 && 0"), "1 && 0")
930*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("0 && 1"), "0 && 1")
931*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("0 && 0"), "0 && 0")
932*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("1 || 1"), "1 || 1")
933*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("1 || 0"), "1 || 0")
934*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("0 || 1"), "0 || 1")
935*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("0 || 0"), "0 || 0")
936*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("EXAMPLE"), "EXAMPLE")
937*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("EXAMPLE - 3"), "EXAMPLE - 3")
938*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("defined(EXAMPLE)"), "defined(EXAMPLE)")
939*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("defined EXAMPLE"), "defined(EXAMPLE)")
940*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_expr_string("A == 1 || defined(B)"), "A == 1 || defined(B)")
941*8d67ca89SAndroid Build Coastguard Worker
942*8d67ca89SAndroid Build Coastguard Worker
943*8d67ca89SAndroid Build Coastguard Worker################################################################################
944*8d67ca89SAndroid Build Coastguard Worker################################################################################
945*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
946*8d67ca89SAndroid Build Coastguard Worker#####          C P P   B L O C K                                           #####
947*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
948*8d67ca89SAndroid Build Coastguard Worker################################################################################
949*8d67ca89SAndroid Build Coastguard Worker################################################################################
950*8d67ca89SAndroid Build Coastguard Worker
951*8d67ca89SAndroid Build Coastguard Worker
952*8d67ca89SAndroid Build Coastguard Workerclass Block(object):
953*8d67ca89SAndroid Build Coastguard Worker    """A class used to model a block of input source text.
954*8d67ca89SAndroid Build Coastguard Worker
955*8d67ca89SAndroid Build Coastguard Worker    There are two block types:
956*8d67ca89SAndroid Build Coastguard Worker      - directive blocks: contain the tokens of a single pre-processor
957*8d67ca89SAndroid Build Coastguard Worker        directive (e.g. #if)
958*8d67ca89SAndroid Build Coastguard Worker      - text blocks, contain the tokens of non-directive blocks
959*8d67ca89SAndroid Build Coastguard Worker
960*8d67ca89SAndroid Build Coastguard Worker    The cpp parser class below will transform an input source file into a list
961*8d67ca89SAndroid Build Coastguard Worker    of Block objects (grouped in a BlockList object for convenience)
962*8d67ca89SAndroid Build Coastguard Worker    """
963*8d67ca89SAndroid Build Coastguard Worker
964*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, tokens, directive=None, lineno=0, identifier=None):
965*8d67ca89SAndroid Build Coastguard Worker        """Initialize a new block, if 'directive' is None, it is a text block.
966*8d67ca89SAndroid Build Coastguard Worker
967*8d67ca89SAndroid Build Coastguard Worker        NOTE: This automatically converts '#ifdef MACRO' into
968*8d67ca89SAndroid Build Coastguard Worker        '#if defined(MACRO)' and '#ifndef MACRO' into '#if !defined(MACRO)'.
969*8d67ca89SAndroid Build Coastguard Worker        """
970*8d67ca89SAndroid Build Coastguard Worker
971*8d67ca89SAndroid Build Coastguard Worker        if directive == "ifdef":
972*8d67ca89SAndroid Build Coastguard Worker            tok = Token()
973*8d67ca89SAndroid Build Coastguard Worker            tok.id = tokDEFINED
974*8d67ca89SAndroid Build Coastguard Worker            tokens = [tok] + tokens
975*8d67ca89SAndroid Build Coastguard Worker            directive = "if"
976*8d67ca89SAndroid Build Coastguard Worker
977*8d67ca89SAndroid Build Coastguard Worker        elif directive == "ifndef":
978*8d67ca89SAndroid Build Coastguard Worker            tok1 = Token()
979*8d67ca89SAndroid Build Coastguard Worker            tok2 = Token()
980*8d67ca89SAndroid Build Coastguard Worker            tok1.id = tokNOT
981*8d67ca89SAndroid Build Coastguard Worker            tok2.id = tokDEFINED
982*8d67ca89SAndroid Build Coastguard Worker            tokens = [tok1, tok2] + tokens
983*8d67ca89SAndroid Build Coastguard Worker            directive = "if"
984*8d67ca89SAndroid Build Coastguard Worker
985*8d67ca89SAndroid Build Coastguard Worker        self.tokens = tokens
986*8d67ca89SAndroid Build Coastguard Worker        self.directive = directive
987*8d67ca89SAndroid Build Coastguard Worker        self.define_id = identifier
988*8d67ca89SAndroid Build Coastguard Worker        if lineno > 0:
989*8d67ca89SAndroid Build Coastguard Worker            self.lineno = lineno
990*8d67ca89SAndroid Build Coastguard Worker        else:
991*8d67ca89SAndroid Build Coastguard Worker            self.lineno = self.tokens[0].location.line
992*8d67ca89SAndroid Build Coastguard Worker
993*8d67ca89SAndroid Build Coastguard Worker        if self.isIf():
994*8d67ca89SAndroid Build Coastguard Worker            self.expr = CppExpr(self.tokens)
995*8d67ca89SAndroid Build Coastguard Worker
996*8d67ca89SAndroid Build Coastguard Worker    def isDirective(self):
997*8d67ca89SAndroid Build Coastguard Worker        """Return True iff this is a directive block."""
998*8d67ca89SAndroid Build Coastguard Worker        return self.directive is not None
999*8d67ca89SAndroid Build Coastguard Worker
1000*8d67ca89SAndroid Build Coastguard Worker    def isConditional(self):
1001*8d67ca89SAndroid Build Coastguard Worker        """Return True iff this is a conditional directive block."""
1002*8d67ca89SAndroid Build Coastguard Worker        return self.directive in ["if", "ifdef", "ifndef", "else", "elif",
1003*8d67ca89SAndroid Build Coastguard Worker                                  "endif"]
1004*8d67ca89SAndroid Build Coastguard Worker
1005*8d67ca89SAndroid Build Coastguard Worker    def isDefine(self):
1006*8d67ca89SAndroid Build Coastguard Worker        """Return the macro name in a #define directive, or None otherwise."""
1007*8d67ca89SAndroid Build Coastguard Worker        if self.directive != "define":
1008*8d67ca89SAndroid Build Coastguard Worker            return None
1009*8d67ca89SAndroid Build Coastguard Worker        return self.define_id
1010*8d67ca89SAndroid Build Coastguard Worker
1011*8d67ca89SAndroid Build Coastguard Worker    def isIf(self):
1012*8d67ca89SAndroid Build Coastguard Worker        """Return True iff this is an #if-like directive block."""
1013*8d67ca89SAndroid Build Coastguard Worker        return self.directive in ["if", "ifdef", "ifndef", "elif"]
1014*8d67ca89SAndroid Build Coastguard Worker
1015*8d67ca89SAndroid Build Coastguard Worker    def isEndif(self):
1016*8d67ca89SAndroid Build Coastguard Worker        """Return True iff this is an #endif directive block."""
1017*8d67ca89SAndroid Build Coastguard Worker        return self.directive == "endif"
1018*8d67ca89SAndroid Build Coastguard Worker
1019*8d67ca89SAndroid Build Coastguard Worker    def isInclude(self):
1020*8d67ca89SAndroid Build Coastguard Worker        """Check whether this is a #include directive.
1021*8d67ca89SAndroid Build Coastguard Worker
1022*8d67ca89SAndroid Build Coastguard Worker        If true, returns the corresponding file name (with brackets or
1023*8d67ca89SAndroid Build Coastguard Worker        double-qoutes). None otherwise.
1024*8d67ca89SAndroid Build Coastguard Worker        """
1025*8d67ca89SAndroid Build Coastguard Worker
1026*8d67ca89SAndroid Build Coastguard Worker        if self.directive != "include":
1027*8d67ca89SAndroid Build Coastguard Worker            return None
1028*8d67ca89SAndroid Build Coastguard Worker        return ''.join([str(x) for x in self.tokens])
1029*8d67ca89SAndroid Build Coastguard Worker
1030*8d67ca89SAndroid Build Coastguard Worker    @staticmethod
1031*8d67ca89SAndroid Build Coastguard Worker    def format_blocks(tokens, indent=0):
1032*8d67ca89SAndroid Build Coastguard Worker        """Return the formatted lines of strings with proper indentation."""
1033*8d67ca89SAndroid Build Coastguard Worker        newline = True
1034*8d67ca89SAndroid Build Coastguard Worker        result = []
1035*8d67ca89SAndroid Build Coastguard Worker        buf = ''
1036*8d67ca89SAndroid Build Coastguard Worker        i = 0
1037*8d67ca89SAndroid Build Coastguard Worker        while i < len(tokens):
1038*8d67ca89SAndroid Build Coastguard Worker            t = tokens[i]
1039*8d67ca89SAndroid Build Coastguard Worker            if t.id == '{':
1040*8d67ca89SAndroid Build Coastguard Worker                buf += ' {'
1041*8d67ca89SAndroid Build Coastguard Worker                result.append(strip_space(buf))
1042*8d67ca89SAndroid Build Coastguard Worker                # Do not indent if this is extern "C" {
1043*8d67ca89SAndroid Build Coastguard Worker                if i < 2 or tokens[i-2].id != 'extern' or tokens[i-1].id != '"C"':
1044*8d67ca89SAndroid Build Coastguard Worker                    indent += 2
1045*8d67ca89SAndroid Build Coastguard Worker                buf = ''
1046*8d67ca89SAndroid Build Coastguard Worker                newline = True
1047*8d67ca89SAndroid Build Coastguard Worker            elif t.id == '}':
1048*8d67ca89SAndroid Build Coastguard Worker                if indent >= 2:
1049*8d67ca89SAndroid Build Coastguard Worker                    indent -= 2
1050*8d67ca89SAndroid Build Coastguard Worker                if not newline:
1051*8d67ca89SAndroid Build Coastguard Worker                    result.append(strip_space(buf))
1052*8d67ca89SAndroid Build Coastguard Worker                # Look ahead to determine if it's the end of line.
1053*8d67ca89SAndroid Build Coastguard Worker                if (i + 1 < len(tokens) and
1054*8d67ca89SAndroid Build Coastguard Worker                    (tokens[i+1].id == ';' or
1055*8d67ca89SAndroid Build Coastguard Worker                     tokens[i+1].id in ['else', '__attribute__',
1056*8d67ca89SAndroid Build Coastguard Worker                                        '__attribute', '__packed'] or
1057*8d67ca89SAndroid Build Coastguard Worker                     tokens[i+1].kind == TokenKind.IDENTIFIER)):
1058*8d67ca89SAndroid Build Coastguard Worker                    buf = ' ' * indent + '}'
1059*8d67ca89SAndroid Build Coastguard Worker                    newline = False
1060*8d67ca89SAndroid Build Coastguard Worker                else:
1061*8d67ca89SAndroid Build Coastguard Worker                    result.append(' ' * indent + '}')
1062*8d67ca89SAndroid Build Coastguard Worker                    buf = ''
1063*8d67ca89SAndroid Build Coastguard Worker                    newline = True
1064*8d67ca89SAndroid Build Coastguard Worker            elif t.id == ';':
1065*8d67ca89SAndroid Build Coastguard Worker                result.append(strip_space(buf) + ';')
1066*8d67ca89SAndroid Build Coastguard Worker                buf = ''
1067*8d67ca89SAndroid Build Coastguard Worker                newline = True
1068*8d67ca89SAndroid Build Coastguard Worker            # We prefer a new line for each constant in enum.
1069*8d67ca89SAndroid Build Coastguard Worker            elif t.id == ',' and t.cursor.kind == CursorKind.ENUM_DECL:
1070*8d67ca89SAndroid Build Coastguard Worker                result.append(strip_space(buf) + ',')
1071*8d67ca89SAndroid Build Coastguard Worker                buf = ''
1072*8d67ca89SAndroid Build Coastguard Worker                newline = True
1073*8d67ca89SAndroid Build Coastguard Worker            else:
1074*8d67ca89SAndroid Build Coastguard Worker                if newline:
1075*8d67ca89SAndroid Build Coastguard Worker                    buf += ' ' * indent + str(t)
1076*8d67ca89SAndroid Build Coastguard Worker                else:
1077*8d67ca89SAndroid Build Coastguard Worker                    buf += ' ' + str(t)
1078*8d67ca89SAndroid Build Coastguard Worker                newline = False
1079*8d67ca89SAndroid Build Coastguard Worker            i += 1
1080*8d67ca89SAndroid Build Coastguard Worker
1081*8d67ca89SAndroid Build Coastguard Worker        if buf:
1082*8d67ca89SAndroid Build Coastguard Worker            result.append(strip_space(buf))
1083*8d67ca89SAndroid Build Coastguard Worker
1084*8d67ca89SAndroid Build Coastguard Worker        return result, indent
1085*8d67ca89SAndroid Build Coastguard Worker
1086*8d67ca89SAndroid Build Coastguard Worker    def write(self, out, indent):
1087*8d67ca89SAndroid Build Coastguard Worker        """Dump the current block."""
1088*8d67ca89SAndroid Build Coastguard Worker        # removeWhiteSpace() will sometimes creates non-directive blocks
1089*8d67ca89SAndroid Build Coastguard Worker        # without any tokens. These come from blocks that only contained
1090*8d67ca89SAndroid Build Coastguard Worker        # empty lines and spaces. They should not be printed in the final
1091*8d67ca89SAndroid Build Coastguard Worker        # output, and then should not be counted for this operation.
1092*8d67ca89SAndroid Build Coastguard Worker        #
1093*8d67ca89SAndroid Build Coastguard Worker        if self.directive is None and not self.tokens:
1094*8d67ca89SAndroid Build Coastguard Worker            return indent
1095*8d67ca89SAndroid Build Coastguard Worker
1096*8d67ca89SAndroid Build Coastguard Worker        if self.directive:
1097*8d67ca89SAndroid Build Coastguard Worker            out.write(str(self) + '\n')
1098*8d67ca89SAndroid Build Coastguard Worker        else:
1099*8d67ca89SAndroid Build Coastguard Worker            lines, indent = self.format_blocks(self.tokens, indent)
1100*8d67ca89SAndroid Build Coastguard Worker            for line in lines:
1101*8d67ca89SAndroid Build Coastguard Worker                out.write(line + '\n')
1102*8d67ca89SAndroid Build Coastguard Worker
1103*8d67ca89SAndroid Build Coastguard Worker        return indent
1104*8d67ca89SAndroid Build Coastguard Worker
1105*8d67ca89SAndroid Build Coastguard Worker    def __repr__(self):
1106*8d67ca89SAndroid Build Coastguard Worker        """Generate the representation of a given block."""
1107*8d67ca89SAndroid Build Coastguard Worker        if self.directive:
1108*8d67ca89SAndroid Build Coastguard Worker            result = "#%s " % self.directive
1109*8d67ca89SAndroid Build Coastguard Worker            if self.isIf():
1110*8d67ca89SAndroid Build Coastguard Worker                result += repr(self.expr)
1111*8d67ca89SAndroid Build Coastguard Worker            else:
1112*8d67ca89SAndroid Build Coastguard Worker                for tok in self.tokens:
1113*8d67ca89SAndroid Build Coastguard Worker                    result += repr(tok)
1114*8d67ca89SAndroid Build Coastguard Worker        else:
1115*8d67ca89SAndroid Build Coastguard Worker            result = ""
1116*8d67ca89SAndroid Build Coastguard Worker            for tok in self.tokens:
1117*8d67ca89SAndroid Build Coastguard Worker                result += repr(tok)
1118*8d67ca89SAndroid Build Coastguard Worker
1119*8d67ca89SAndroid Build Coastguard Worker        return result
1120*8d67ca89SAndroid Build Coastguard Worker
1121*8d67ca89SAndroid Build Coastguard Worker    def __str__(self):
1122*8d67ca89SAndroid Build Coastguard Worker        """Generate the string representation of a given block."""
1123*8d67ca89SAndroid Build Coastguard Worker        if self.directive:
1124*8d67ca89SAndroid Build Coastguard Worker            # "#if"
1125*8d67ca89SAndroid Build Coastguard Worker            if self.directive == "if":
1126*8d67ca89SAndroid Build Coastguard Worker                # small optimization to re-generate #ifdef and #ifndef
1127*8d67ca89SAndroid Build Coastguard Worker                e = self.expr.expr
1128*8d67ca89SAndroid Build Coastguard Worker                op = e[0]
1129*8d67ca89SAndroid Build Coastguard Worker                if op == "defined":
1130*8d67ca89SAndroid Build Coastguard Worker                    result = "#ifdef %s" % e[1]
1131*8d67ca89SAndroid Build Coastguard Worker                elif op == "!" and e[1][0] == "defined":
1132*8d67ca89SAndroid Build Coastguard Worker                    result = "#ifndef %s" % e[1][1]
1133*8d67ca89SAndroid Build Coastguard Worker                else:
1134*8d67ca89SAndroid Build Coastguard Worker                    result = "#if " + str(self.expr)
1135*8d67ca89SAndroid Build Coastguard Worker
1136*8d67ca89SAndroid Build Coastguard Worker            # "#define"
1137*8d67ca89SAndroid Build Coastguard Worker            elif self.isDefine():
1138*8d67ca89SAndroid Build Coastguard Worker                result = "#%s %s" % (self.directive, self.define_id)
1139*8d67ca89SAndroid Build Coastguard Worker                if self.tokens:
1140*8d67ca89SAndroid Build Coastguard Worker                    result += " "
1141*8d67ca89SAndroid Build Coastguard Worker                expr = strip_space(' '.join([tok.id for tok in self.tokens]))
1142*8d67ca89SAndroid Build Coastguard Worker                # remove the space between name and '(' in function call
1143*8d67ca89SAndroid Build Coastguard Worker                result += re.sub(r'(\w+) \(', r'\1(', expr)
1144*8d67ca89SAndroid Build Coastguard Worker
1145*8d67ca89SAndroid Build Coastguard Worker            # "#error"
1146*8d67ca89SAndroid Build Coastguard Worker            # Concatenating tokens with a space separator, because they may
1147*8d67ca89SAndroid Build Coastguard Worker            # not be quoted and broken into several tokens
1148*8d67ca89SAndroid Build Coastguard Worker            elif self.directive == "error":
1149*8d67ca89SAndroid Build Coastguard Worker                result = "#error %s" % ' '.join([tok.id for tok in self.tokens])
1150*8d67ca89SAndroid Build Coastguard Worker
1151*8d67ca89SAndroid Build Coastguard Worker            else:
1152*8d67ca89SAndroid Build Coastguard Worker                result = "#%s" % self.directive
1153*8d67ca89SAndroid Build Coastguard Worker                if self.tokens:
1154*8d67ca89SAndroid Build Coastguard Worker                    result += " "
1155*8d67ca89SAndroid Build Coastguard Worker                result += ''.join([tok.id for tok in self.tokens])
1156*8d67ca89SAndroid Build Coastguard Worker        else:
1157*8d67ca89SAndroid Build Coastguard Worker            lines, _ = self.format_blocks(self.tokens)
1158*8d67ca89SAndroid Build Coastguard Worker            result = '\n'.join(lines)
1159*8d67ca89SAndroid Build Coastguard Worker
1160*8d67ca89SAndroid Build Coastguard Worker        return result
1161*8d67ca89SAndroid Build Coastguard Worker
1162*8d67ca89SAndroid Build Coastguard Worker
1163*8d67ca89SAndroid Build Coastguard Workerclass BlockList(object):
1164*8d67ca89SAndroid Build Coastguard Worker    """A convenience class used to hold and process a list of blocks.
1165*8d67ca89SAndroid Build Coastguard Worker
1166*8d67ca89SAndroid Build Coastguard Worker    It calls the cpp parser to get the blocks.
1167*8d67ca89SAndroid Build Coastguard Worker    """
1168*8d67ca89SAndroid Build Coastguard Worker
1169*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, blocks):
1170*8d67ca89SAndroid Build Coastguard Worker        self.blocks = blocks
1171*8d67ca89SAndroid Build Coastguard Worker
1172*8d67ca89SAndroid Build Coastguard Worker    def __len__(self):
1173*8d67ca89SAndroid Build Coastguard Worker        return len(self.blocks)
1174*8d67ca89SAndroid Build Coastguard Worker
1175*8d67ca89SAndroid Build Coastguard Worker    def __getitem__(self, n):
1176*8d67ca89SAndroid Build Coastguard Worker        return self.blocks[n]
1177*8d67ca89SAndroid Build Coastguard Worker
1178*8d67ca89SAndroid Build Coastguard Worker    def __repr__(self):
1179*8d67ca89SAndroid Build Coastguard Worker        return repr(self.blocks)
1180*8d67ca89SAndroid Build Coastguard Worker
1181*8d67ca89SAndroid Build Coastguard Worker    def __str__(self):
1182*8d67ca89SAndroid Build Coastguard Worker        result = '\n'.join([str(b) for b in self.blocks])
1183*8d67ca89SAndroid Build Coastguard Worker        return result
1184*8d67ca89SAndroid Build Coastguard Worker
1185*8d67ca89SAndroid Build Coastguard Worker    def dump(self):
1186*8d67ca89SAndroid Build Coastguard Worker        """Dump all the blocks in current BlockList."""
1187*8d67ca89SAndroid Build Coastguard Worker        print('##### BEGIN #####')
1188*8d67ca89SAndroid Build Coastguard Worker        for i, b in enumerate(self.blocks):
1189*8d67ca89SAndroid Build Coastguard Worker            print('### BLOCK %d ###' % i)
1190*8d67ca89SAndroid Build Coastguard Worker            print(b)
1191*8d67ca89SAndroid Build Coastguard Worker        print('##### END #####')
1192*8d67ca89SAndroid Build Coastguard Worker
1193*8d67ca89SAndroid Build Coastguard Worker    def optimizeIf01(self):
1194*8d67ca89SAndroid Build Coastguard Worker        """Remove the code between #if 0 .. #endif in a BlockList."""
1195*8d67ca89SAndroid Build Coastguard Worker        self.blocks = optimize_if01(self.blocks)
1196*8d67ca89SAndroid Build Coastguard Worker
1197*8d67ca89SAndroid Build Coastguard Worker    def optimizeMacros(self, macros):
1198*8d67ca89SAndroid Build Coastguard Worker        """Remove known defined and undefined macros from a BlockList."""
1199*8d67ca89SAndroid Build Coastguard Worker        for b in self.blocks:
1200*8d67ca89SAndroid Build Coastguard Worker            if b.isIf():
1201*8d67ca89SAndroid Build Coastguard Worker                b.expr.optimize(macros)
1202*8d67ca89SAndroid Build Coastguard Worker
1203*8d67ca89SAndroid Build Coastguard Worker    def removeStructs(self, structs):
1204*8d67ca89SAndroid Build Coastguard Worker        """Remove structs."""
1205*8d67ca89SAndroid Build Coastguard Worker        extra_includes = set()
1206*8d67ca89SAndroid Build Coastguard Worker        block_num = 0
1207*8d67ca89SAndroid Build Coastguard Worker        num_blocks = len(self.blocks)
1208*8d67ca89SAndroid Build Coastguard Worker        while block_num < num_blocks:
1209*8d67ca89SAndroid Build Coastguard Worker            b = self.blocks[block_num]
1210*8d67ca89SAndroid Build Coastguard Worker            block_num += 1
1211*8d67ca89SAndroid Build Coastguard Worker            # Have to look in each block for a top-level struct definition.
1212*8d67ca89SAndroid Build Coastguard Worker            if b.directive:
1213*8d67ca89SAndroid Build Coastguard Worker                continue
1214*8d67ca89SAndroid Build Coastguard Worker            num_tokens = len(b.tokens)
1215*8d67ca89SAndroid Build Coastguard Worker            # A struct definition usually looks like:
1216*8d67ca89SAndroid Build Coastguard Worker            #   struct
1217*8d67ca89SAndroid Build Coastguard Worker            #   ident
1218*8d67ca89SAndroid Build Coastguard Worker            #   {
1219*8d67ca89SAndroid Build Coastguard Worker            #   }
1220*8d67ca89SAndroid Build Coastguard Worker            #   ;
1221*8d67ca89SAndroid Build Coastguard Worker            # However, the structure might be spread across multiple blocks
1222*8d67ca89SAndroid Build Coastguard Worker            # if the structure looks like this:
1223*8d67ca89SAndroid Build Coastguard Worker            #   struct ident
1224*8d67ca89SAndroid Build Coastguard Worker            #   {
1225*8d67ca89SAndroid Build Coastguard Worker            #   #ifdef VARIABLE
1226*8d67ca89SAndroid Build Coastguard Worker            #     pid_t pid;
1227*8d67ca89SAndroid Build Coastguard Worker            #   #endif
1228*8d67ca89SAndroid Build Coastguard Worker            #   }:
1229*8d67ca89SAndroid Build Coastguard Worker            # So the total number of tokens in the block might be less than
1230*8d67ca89SAndroid Build Coastguard Worker            # five but assume at least three.
1231*8d67ca89SAndroid Build Coastguard Worker            if num_tokens < 3:
1232*8d67ca89SAndroid Build Coastguard Worker                continue
1233*8d67ca89SAndroid Build Coastguard Worker
1234*8d67ca89SAndroid Build Coastguard Worker            # This is a simple struct finder, it might fail if a top-level
1235*8d67ca89SAndroid Build Coastguard Worker            # structure has an #if type directives that confuses the algorithm
1236*8d67ca89SAndroid Build Coastguard Worker            # for finding the end of the structure. Or if there is another
1237*8d67ca89SAndroid Build Coastguard Worker            # structure definition embedded in the structure.
1238*8d67ca89SAndroid Build Coastguard Worker            i = 0
1239*8d67ca89SAndroid Build Coastguard Worker            while i < num_tokens - 2:
1240*8d67ca89SAndroid Build Coastguard Worker                if (b.tokens[i].kind != TokenKind.KEYWORD or
1241*8d67ca89SAndroid Build Coastguard Worker                    b.tokens[i].id != "struct"):
1242*8d67ca89SAndroid Build Coastguard Worker                    i += 1
1243*8d67ca89SAndroid Build Coastguard Worker                    continue
1244*8d67ca89SAndroid Build Coastguard Worker                if (b.tokens[i + 1].kind == TokenKind.IDENTIFIER and
1245*8d67ca89SAndroid Build Coastguard Worker                    b.tokens[i + 2].kind == TokenKind.PUNCTUATION and
1246*8d67ca89SAndroid Build Coastguard Worker                    b.tokens[i + 2].id == "{" and b.tokens[i + 1].id in structs):
1247*8d67ca89SAndroid Build Coastguard Worker                    # Add an include for the structure to be removed of the form:
1248*8d67ca89SAndroid Build Coastguard Worker                    #  #include <bits/STRUCT_NAME.h>
1249*8d67ca89SAndroid Build Coastguard Worker                    struct_token = b.tokens[i + 1]
1250*8d67ca89SAndroid Build Coastguard Worker                    if struct_token.id in structs and structs[struct_token.id]:
1251*8d67ca89SAndroid Build Coastguard Worker                        extra_includes.add("<%s>" % structs[struct_token.id])
1252*8d67ca89SAndroid Build Coastguard Worker
1253*8d67ca89SAndroid Build Coastguard Worker                    # Search forward for the end of the structure.
1254*8d67ca89SAndroid Build Coastguard Worker                    # Very simple search, look for } and ; tokens.
1255*8d67ca89SAndroid Build Coastguard Worker                    # If we hit the end of the block, we'll need to start
1256*8d67ca89SAndroid Build Coastguard Worker                    # looking at the next block.
1257*8d67ca89SAndroid Build Coastguard Worker                    j = i + 3
1258*8d67ca89SAndroid Build Coastguard Worker                    depth = 1
1259*8d67ca89SAndroid Build Coastguard Worker                    struct_removed = False
1260*8d67ca89SAndroid Build Coastguard Worker                    while not struct_removed:
1261*8d67ca89SAndroid Build Coastguard Worker                        while j < num_tokens:
1262*8d67ca89SAndroid Build Coastguard Worker                            if b.tokens[j].kind == TokenKind.PUNCTUATION:
1263*8d67ca89SAndroid Build Coastguard Worker                                if b.tokens[j].id == '{':
1264*8d67ca89SAndroid Build Coastguard Worker                                    depth += 1
1265*8d67ca89SAndroid Build Coastguard Worker                                elif b.tokens[j].id == '}':
1266*8d67ca89SAndroid Build Coastguard Worker                                    depth -= 1
1267*8d67ca89SAndroid Build Coastguard Worker                                elif b.tokens[j].id == ';' and depth == 0:
1268*8d67ca89SAndroid Build Coastguard Worker                                    b.tokens = b.tokens[0:i] + b.tokens[j + 1:num_tokens]
1269*8d67ca89SAndroid Build Coastguard Worker                                    num_tokens = len(b.tokens)
1270*8d67ca89SAndroid Build Coastguard Worker                                    struct_removed = True
1271*8d67ca89SAndroid Build Coastguard Worker                                    break
1272*8d67ca89SAndroid Build Coastguard Worker                            j += 1
1273*8d67ca89SAndroid Build Coastguard Worker                        if not struct_removed:
1274*8d67ca89SAndroid Build Coastguard Worker                            b.tokens = b.tokens[0:i]
1275*8d67ca89SAndroid Build Coastguard Worker
1276*8d67ca89SAndroid Build Coastguard Worker                            # Skip directive blocks.
1277*8d67ca89SAndroid Build Coastguard Worker                            start_block = block_num
1278*8d67ca89SAndroid Build Coastguard Worker                            while block_num < num_blocks:
1279*8d67ca89SAndroid Build Coastguard Worker                                if not self.blocks[block_num].directive:
1280*8d67ca89SAndroid Build Coastguard Worker                                    break
1281*8d67ca89SAndroid Build Coastguard Worker                                block_num += 1
1282*8d67ca89SAndroid Build Coastguard Worker                            if block_num >= num_blocks:
1283*8d67ca89SAndroid Build Coastguard Worker                                # Unparsable struct, error out.
1284*8d67ca89SAndroid Build Coastguard Worker                                raise UnparseableStruct("Cannot remove struct %s: %s" % (struct_token.id, struct_token.location))
1285*8d67ca89SAndroid Build Coastguard Worker                            self.blocks = self.blocks[0:start_block] + self.blocks[block_num:num_blocks]
1286*8d67ca89SAndroid Build Coastguard Worker                            num_blocks = len(self.blocks)
1287*8d67ca89SAndroid Build Coastguard Worker                            b = self.blocks[start_block]
1288*8d67ca89SAndroid Build Coastguard Worker                            block_num = start_block + 1
1289*8d67ca89SAndroid Build Coastguard Worker                            num_tokens = len(b.tokens)
1290*8d67ca89SAndroid Build Coastguard Worker                            i = 0
1291*8d67ca89SAndroid Build Coastguard Worker                            j = 0
1292*8d67ca89SAndroid Build Coastguard Worker                    continue
1293*8d67ca89SAndroid Build Coastguard Worker                i += 1
1294*8d67ca89SAndroid Build Coastguard Worker
1295*8d67ca89SAndroid Build Coastguard Worker        for extra_include in sorted(extra_includes):
1296*8d67ca89SAndroid Build Coastguard Worker            replacement = CppStringTokenizer(extra_include)
1297*8d67ca89SAndroid Build Coastguard Worker            self.blocks.insert(2, Block(replacement.tokens, directive='include'))
1298*8d67ca89SAndroid Build Coastguard Worker
1299*8d67ca89SAndroid Build Coastguard Worker    def optimizeAll(self, macros):
1300*8d67ca89SAndroid Build Coastguard Worker        self.optimizeMacros(macros)
1301*8d67ca89SAndroid Build Coastguard Worker        self.optimizeIf01()
1302*8d67ca89SAndroid Build Coastguard Worker        return
1303*8d67ca89SAndroid Build Coastguard Worker
1304*8d67ca89SAndroid Build Coastguard Worker    def findIncludes(self):
1305*8d67ca89SAndroid Build Coastguard Worker        """Return the list of included files in a BlockList."""
1306*8d67ca89SAndroid Build Coastguard Worker        result = []
1307*8d67ca89SAndroid Build Coastguard Worker        for b in self.blocks:
1308*8d67ca89SAndroid Build Coastguard Worker            i = b.isInclude()
1309*8d67ca89SAndroid Build Coastguard Worker            if i:
1310*8d67ca89SAndroid Build Coastguard Worker                result.append(i)
1311*8d67ca89SAndroid Build Coastguard Worker        return result
1312*8d67ca89SAndroid Build Coastguard Worker
1313*8d67ca89SAndroid Build Coastguard Worker    def write(self, out):
1314*8d67ca89SAndroid Build Coastguard Worker        indent = 0
1315*8d67ca89SAndroid Build Coastguard Worker        for b in self.blocks:
1316*8d67ca89SAndroid Build Coastguard Worker            indent = b.write(out, indent)
1317*8d67ca89SAndroid Build Coastguard Worker
1318*8d67ca89SAndroid Build Coastguard Worker    def removeVarsAndFuncs(self, keep):
1319*8d67ca89SAndroid Build Coastguard Worker        """Remove variable and function declarations.
1320*8d67ca89SAndroid Build Coastguard Worker
1321*8d67ca89SAndroid Build Coastguard Worker        All extern and static declarations corresponding to variable and
1322*8d67ca89SAndroid Build Coastguard Worker        function declarations are removed. We only accept typedefs and
1323*8d67ca89SAndroid Build Coastguard Worker        enum/structs/union declarations.
1324*8d67ca89SAndroid Build Coastguard Worker
1325*8d67ca89SAndroid Build Coastguard Worker        In addition, remove any macros expanding in the headers. Usually,
1326*8d67ca89SAndroid Build Coastguard Worker        these macros are static inline functions, which is why they are
1327*8d67ca89SAndroid Build Coastguard Worker        removed.
1328*8d67ca89SAndroid Build Coastguard Worker
1329*8d67ca89SAndroid Build Coastguard Worker        However, we keep the definitions corresponding to the set of known
1330*8d67ca89SAndroid Build Coastguard Worker        static inline functions in the set 'keep', which is useful
1331*8d67ca89SAndroid Build Coastguard Worker        for optimized byteorder swap functions and stuff like that.
1332*8d67ca89SAndroid Build Coastguard Worker        """
1333*8d67ca89SAndroid Build Coastguard Worker
1334*8d67ca89SAndroid Build Coastguard Worker        # state = NORMAL => normal (i.e. LN + spaces)
1335*8d67ca89SAndroid Build Coastguard Worker        # state = OTHER_DECL => typedef/struct encountered, ends with ";"
1336*8d67ca89SAndroid Build Coastguard Worker        # state = VAR_DECL => var declaration encountered, ends with ";"
1337*8d67ca89SAndroid Build Coastguard Worker        # state = FUNC_DECL => func declaration encountered, ends with "}"
1338*8d67ca89SAndroid Build Coastguard Worker        NORMAL = 0
1339*8d67ca89SAndroid Build Coastguard Worker        OTHER_DECL = 1
1340*8d67ca89SAndroid Build Coastguard Worker        VAR_DECL = 2
1341*8d67ca89SAndroid Build Coastguard Worker        FUNC_DECL = 3
1342*8d67ca89SAndroid Build Coastguard Worker
1343*8d67ca89SAndroid Build Coastguard Worker        state = NORMAL
1344*8d67ca89SAndroid Build Coastguard Worker        depth = 0
1345*8d67ca89SAndroid Build Coastguard Worker        blocksToKeep = []
1346*8d67ca89SAndroid Build Coastguard Worker        blocksInProgress = []
1347*8d67ca89SAndroid Build Coastguard Worker        blocksOfDirectives = []
1348*8d67ca89SAndroid Build Coastguard Worker        ident = ""
1349*8d67ca89SAndroid Build Coastguard Worker        state_token = ""
1350*8d67ca89SAndroid Build Coastguard Worker        macros = set()
1351*8d67ca89SAndroid Build Coastguard Worker        for block in self.blocks:
1352*8d67ca89SAndroid Build Coastguard Worker            if block.isDirective():
1353*8d67ca89SAndroid Build Coastguard Worker                # Record all macros.
1354*8d67ca89SAndroid Build Coastguard Worker                if block.directive == 'define':
1355*8d67ca89SAndroid Build Coastguard Worker                    macro_name = block.define_id
1356*8d67ca89SAndroid Build Coastguard Worker                    paren_index = macro_name.find('(')
1357*8d67ca89SAndroid Build Coastguard Worker                    if paren_index == -1:
1358*8d67ca89SAndroid Build Coastguard Worker                        macros.add(macro_name)
1359*8d67ca89SAndroid Build Coastguard Worker                    else:
1360*8d67ca89SAndroid Build Coastguard Worker                        macros.add(macro_name[0:paren_index])
1361*8d67ca89SAndroid Build Coastguard Worker                blocksInProgress.append(block)
1362*8d67ca89SAndroid Build Coastguard Worker                # If this is in a function/variable declaration, we might need
1363*8d67ca89SAndroid Build Coastguard Worker                # to emit the directives alone, so save them separately.
1364*8d67ca89SAndroid Build Coastguard Worker                blocksOfDirectives.append(block)
1365*8d67ca89SAndroid Build Coastguard Worker                continue
1366*8d67ca89SAndroid Build Coastguard Worker
1367*8d67ca89SAndroid Build Coastguard Worker            numTokens = len(block.tokens)
1368*8d67ca89SAndroid Build Coastguard Worker            lastTerminatorIndex = 0
1369*8d67ca89SAndroid Build Coastguard Worker            i = 0
1370*8d67ca89SAndroid Build Coastguard Worker            while i < numTokens:
1371*8d67ca89SAndroid Build Coastguard Worker                token_id = block.tokens[i].id
1372*8d67ca89SAndroid Build Coastguard Worker                terminator = False
1373*8d67ca89SAndroid Build Coastguard Worker                if token_id == '{':
1374*8d67ca89SAndroid Build Coastguard Worker                    depth += 1
1375*8d67ca89SAndroid Build Coastguard Worker                    if (i >= 2 and block.tokens[i-2].id == 'extern' and
1376*8d67ca89SAndroid Build Coastguard Worker                        block.tokens[i-1].id == '"C"'):
1377*8d67ca89SAndroid Build Coastguard Worker                        # For an extern "C" { pretend as though this is depth 0.
1378*8d67ca89SAndroid Build Coastguard Worker                        depth -= 1
1379*8d67ca89SAndroid Build Coastguard Worker                elif token_id == '}':
1380*8d67ca89SAndroid Build Coastguard Worker                    if depth > 0:
1381*8d67ca89SAndroid Build Coastguard Worker                        depth -= 1
1382*8d67ca89SAndroid Build Coastguard Worker                    if depth == 0:
1383*8d67ca89SAndroid Build Coastguard Worker                        if state == OTHER_DECL:
1384*8d67ca89SAndroid Build Coastguard Worker                            # Loop through until we hit the ';'
1385*8d67ca89SAndroid Build Coastguard Worker                            i += 1
1386*8d67ca89SAndroid Build Coastguard Worker                            while i < numTokens:
1387*8d67ca89SAndroid Build Coastguard Worker                                if block.tokens[i].id == ';':
1388*8d67ca89SAndroid Build Coastguard Worker                                    token_id = ';'
1389*8d67ca89SAndroid Build Coastguard Worker                                    break
1390*8d67ca89SAndroid Build Coastguard Worker                                i += 1
1391*8d67ca89SAndroid Build Coastguard Worker                            # If we didn't hit the ';', just consider this the
1392*8d67ca89SAndroid Build Coastguard Worker                            # terminator any way.
1393*8d67ca89SAndroid Build Coastguard Worker                        terminator = True
1394*8d67ca89SAndroid Build Coastguard Worker                elif depth == 0:
1395*8d67ca89SAndroid Build Coastguard Worker                    if token_id == ';':
1396*8d67ca89SAndroid Build Coastguard Worker                        if state == NORMAL:
1397*8d67ca89SAndroid Build Coastguard Worker                            blocksToKeep.extend(blocksInProgress)
1398*8d67ca89SAndroid Build Coastguard Worker                            blocksInProgress = []
1399*8d67ca89SAndroid Build Coastguard Worker                            blocksOfDirectives = []
1400*8d67ca89SAndroid Build Coastguard Worker                            state = FUNC_DECL
1401*8d67ca89SAndroid Build Coastguard Worker                        terminator = True
1402*8d67ca89SAndroid Build Coastguard Worker                    elif (state == NORMAL and token_id == '(' and i >= 1 and
1403*8d67ca89SAndroid Build Coastguard Worker                          block.tokens[i-1].kind == TokenKind.IDENTIFIER and
1404*8d67ca89SAndroid Build Coastguard Worker                          block.tokens[i-1].id in macros):
1405*8d67ca89SAndroid Build Coastguard Worker                        # This is a plain macro being expanded in the header
1406*8d67ca89SAndroid Build Coastguard Worker                        # which needs to be removed.
1407*8d67ca89SAndroid Build Coastguard Worker                        blocksToKeep.extend(blocksInProgress)
1408*8d67ca89SAndroid Build Coastguard Worker                        if lastTerminatorIndex < i - 1:
1409*8d67ca89SAndroid Build Coastguard Worker                            blocksToKeep.append(Block(block.tokens[lastTerminatorIndex:i-1]))
1410*8d67ca89SAndroid Build Coastguard Worker                        blocksInProgress = []
1411*8d67ca89SAndroid Build Coastguard Worker                        blocksOfDirectives = []
1412*8d67ca89SAndroid Build Coastguard Worker
1413*8d67ca89SAndroid Build Coastguard Worker                        # Skip until we see the terminating ')'
1414*8d67ca89SAndroid Build Coastguard Worker                        i += 1
1415*8d67ca89SAndroid Build Coastguard Worker                        paren_depth = 1
1416*8d67ca89SAndroid Build Coastguard Worker                        while i < numTokens:
1417*8d67ca89SAndroid Build Coastguard Worker                            if block.tokens[i].id == ')':
1418*8d67ca89SAndroid Build Coastguard Worker                                paren_depth -= 1
1419*8d67ca89SAndroid Build Coastguard Worker                                if paren_depth == 0:
1420*8d67ca89SAndroid Build Coastguard Worker                                    break
1421*8d67ca89SAndroid Build Coastguard Worker                            elif block.tokens[i].id == '(':
1422*8d67ca89SAndroid Build Coastguard Worker                                paren_depth += 1
1423*8d67ca89SAndroid Build Coastguard Worker                            i += 1
1424*8d67ca89SAndroid Build Coastguard Worker                        lastTerminatorIndex = i + 1
1425*8d67ca89SAndroid Build Coastguard Worker                    elif (state != FUNC_DECL and token_id == '(' and
1426*8d67ca89SAndroid Build Coastguard Worker                          state_token != 'typedef'):
1427*8d67ca89SAndroid Build Coastguard Worker                        blocksToKeep.extend(blocksInProgress)
1428*8d67ca89SAndroid Build Coastguard Worker                        blocksInProgress = []
1429*8d67ca89SAndroid Build Coastguard Worker                        blocksOfDirectives = []
1430*8d67ca89SAndroid Build Coastguard Worker                        state = VAR_DECL
1431*8d67ca89SAndroid Build Coastguard Worker                    elif state == NORMAL and token_id in ['struct', 'typedef',
1432*8d67ca89SAndroid Build Coastguard Worker                                                          'enum', 'union',
1433*8d67ca89SAndroid Build Coastguard Worker                                                          '__extension__', '=']:
1434*8d67ca89SAndroid Build Coastguard Worker                        state = OTHER_DECL
1435*8d67ca89SAndroid Build Coastguard Worker                        state_token = token_id
1436*8d67ca89SAndroid Build Coastguard Worker                    elif block.tokens[i].kind == TokenKind.IDENTIFIER:
1437*8d67ca89SAndroid Build Coastguard Worker                        if state != VAR_DECL or ident == "":
1438*8d67ca89SAndroid Build Coastguard Worker                            ident = token_id
1439*8d67ca89SAndroid Build Coastguard Worker
1440*8d67ca89SAndroid Build Coastguard Worker                if terminator:
1441*8d67ca89SAndroid Build Coastguard Worker                    if state != VAR_DECL and state != FUNC_DECL or ident in keep:
1442*8d67ca89SAndroid Build Coastguard Worker                        blocksInProgress.append(Block(block.tokens[lastTerminatorIndex:i+1]))
1443*8d67ca89SAndroid Build Coastguard Worker                        blocksToKeep.extend(blocksInProgress)
1444*8d67ca89SAndroid Build Coastguard Worker                    else:
1445*8d67ca89SAndroid Build Coastguard Worker                        # Only keep the directives found.
1446*8d67ca89SAndroid Build Coastguard Worker                        blocksToKeep.extend(blocksOfDirectives)
1447*8d67ca89SAndroid Build Coastguard Worker                    lastTerminatorIndex = i + 1
1448*8d67ca89SAndroid Build Coastguard Worker                    blocksInProgress = []
1449*8d67ca89SAndroid Build Coastguard Worker                    blocksOfDirectives = []
1450*8d67ca89SAndroid Build Coastguard Worker                    state = NORMAL
1451*8d67ca89SAndroid Build Coastguard Worker                    ident = ""
1452*8d67ca89SAndroid Build Coastguard Worker                    state_token = ""
1453*8d67ca89SAndroid Build Coastguard Worker                i += 1
1454*8d67ca89SAndroid Build Coastguard Worker            if lastTerminatorIndex < numTokens:
1455*8d67ca89SAndroid Build Coastguard Worker                blocksInProgress.append(Block(block.tokens[lastTerminatorIndex:numTokens]))
1456*8d67ca89SAndroid Build Coastguard Worker        if len(blocksInProgress) > 0:
1457*8d67ca89SAndroid Build Coastguard Worker            blocksToKeep.extend(blocksInProgress)
1458*8d67ca89SAndroid Build Coastguard Worker        self.blocks = blocksToKeep
1459*8d67ca89SAndroid Build Coastguard Worker
1460*8d67ca89SAndroid Build Coastguard Worker    def replaceTokens(self, replacements):
1461*8d67ca89SAndroid Build Coastguard Worker        """Replace tokens according to the given dict."""
1462*8d67ca89SAndroid Build Coastguard Worker        for b in self.blocks:
1463*8d67ca89SAndroid Build Coastguard Worker            made_change = False
1464*8d67ca89SAndroid Build Coastguard Worker            if b.isInclude() is None:
1465*8d67ca89SAndroid Build Coastguard Worker                i = 0
1466*8d67ca89SAndroid Build Coastguard Worker                while i < len(b.tokens):
1467*8d67ca89SAndroid Build Coastguard Worker                    tok = b.tokens[i]
1468*8d67ca89SAndroid Build Coastguard Worker                    if tok.kind == TokenKind.IDENTIFIER:
1469*8d67ca89SAndroid Build Coastguard Worker                        if tok.id in replacements:
1470*8d67ca89SAndroid Build Coastguard Worker                            tok.id = replacements[tok.id]
1471*8d67ca89SAndroid Build Coastguard Worker                            made_change = True
1472*8d67ca89SAndroid Build Coastguard Worker                    i += 1
1473*8d67ca89SAndroid Build Coastguard Worker
1474*8d67ca89SAndroid Build Coastguard Worker                if b.isDefine():
1475*8d67ca89SAndroid Build Coastguard Worker                    tokens = CppStringTokenizer(b.define_id).tokens
1476*8d67ca89SAndroid Build Coastguard Worker                    id_change = False
1477*8d67ca89SAndroid Build Coastguard Worker                    for tok in tokens:
1478*8d67ca89SAndroid Build Coastguard Worker                        if tok.kind == TokenKind.IDENTIFIER:
1479*8d67ca89SAndroid Build Coastguard Worker                            if tok.id in replacements:
1480*8d67ca89SAndroid Build Coastguard Worker                                tok.id = replacements[tok.id]
1481*8d67ca89SAndroid Build Coastguard Worker                                id_change = True
1482*8d67ca89SAndroid Build Coastguard Worker                    if id_change:
1483*8d67ca89SAndroid Build Coastguard Worker                        b.define_id = ''.join([tok.id for tok in tokens])
1484*8d67ca89SAndroid Build Coastguard Worker                        made_change = True
1485*8d67ca89SAndroid Build Coastguard Worker
1486*8d67ca89SAndroid Build Coastguard Worker
1487*8d67ca89SAndroid Build Coastguard Worker            if made_change and b.isIf():
1488*8d67ca89SAndroid Build Coastguard Worker                # Keep 'expr' in sync with 'tokens'.
1489*8d67ca89SAndroid Build Coastguard Worker                b.expr = CppExpr(b.tokens)
1490*8d67ca89SAndroid Build Coastguard Worker
1491*8d67ca89SAndroid Build Coastguard Worker
1492*8d67ca89SAndroid Build Coastguard Worker
1493*8d67ca89SAndroid Build Coastguard Workerdef strip_space(s):
1494*8d67ca89SAndroid Build Coastguard Worker    """Strip out redundant space in a given string."""
1495*8d67ca89SAndroid Build Coastguard Worker
1496*8d67ca89SAndroid Build Coastguard Worker    # NOTE: It ought to be more clever to not destroy spaces in string tokens.
1497*8d67ca89SAndroid Build Coastguard Worker    replacements = {' . ': '.',
1498*8d67ca89SAndroid Build Coastguard Worker                    ' [': '[',
1499*8d67ca89SAndroid Build Coastguard Worker                    '[ ': '[',
1500*8d67ca89SAndroid Build Coastguard Worker                    ' ]': ']',
1501*8d67ca89SAndroid Build Coastguard Worker                    '( ': '(',
1502*8d67ca89SAndroid Build Coastguard Worker                    ' )': ')',
1503*8d67ca89SAndroid Build Coastguard Worker                    ' ,': ',',
1504*8d67ca89SAndroid Build Coastguard Worker                    '# ': '#',
1505*8d67ca89SAndroid Build Coastguard Worker                    ' ;': ';',
1506*8d67ca89SAndroid Build Coastguard Worker                    '~ ': '~',
1507*8d67ca89SAndroid Build Coastguard Worker                    ' -> ': '->'}
1508*8d67ca89SAndroid Build Coastguard Worker    result = s
1509*8d67ca89SAndroid Build Coastguard Worker    for r in replacements:
1510*8d67ca89SAndroid Build Coastguard Worker        result = result.replace(r, replacements[r])
1511*8d67ca89SAndroid Build Coastguard Worker
1512*8d67ca89SAndroid Build Coastguard Worker    # Remove the space between function name and the parenthesis.
1513*8d67ca89SAndroid Build Coastguard Worker    result = re.sub(r'(\w+) \(', r'\1(', result)
1514*8d67ca89SAndroid Build Coastguard Worker    return result
1515*8d67ca89SAndroid Build Coastguard Worker
1516*8d67ca89SAndroid Build Coastguard Worker
1517*8d67ca89SAndroid Build Coastguard Workerclass BlockParser(object):
1518*8d67ca89SAndroid Build Coastguard Worker    """A class that converts an input source file into a BlockList object."""
1519*8d67ca89SAndroid Build Coastguard Worker
1520*8d67ca89SAndroid Build Coastguard Worker    def __init__(self, tokzer=None):
1521*8d67ca89SAndroid Build Coastguard Worker        """Initialize a block parser.
1522*8d67ca89SAndroid Build Coastguard Worker
1523*8d67ca89SAndroid Build Coastguard Worker        The input source is provided through a Tokenizer object.
1524*8d67ca89SAndroid Build Coastguard Worker        """
1525*8d67ca89SAndroid Build Coastguard Worker        self._tokzer = tokzer
1526*8d67ca89SAndroid Build Coastguard Worker        self._parsed = False
1527*8d67ca89SAndroid Build Coastguard Worker
1528*8d67ca89SAndroid Build Coastguard Worker    @property
1529*8d67ca89SAndroid Build Coastguard Worker    def parsed(self):
1530*8d67ca89SAndroid Build Coastguard Worker        return self._parsed
1531*8d67ca89SAndroid Build Coastguard Worker
1532*8d67ca89SAndroid Build Coastguard Worker    @staticmethod
1533*8d67ca89SAndroid Build Coastguard Worker    def _short_extent(extent):
1534*8d67ca89SAndroid Build Coastguard Worker        return '%d:%d - %d:%d' % (extent.start.line, extent.start.column,
1535*8d67ca89SAndroid Build Coastguard Worker                                  extent.end.line, extent.end.column)
1536*8d67ca89SAndroid Build Coastguard Worker
1537*8d67ca89SAndroid Build Coastguard Worker    def getBlocks(self, tokzer=None):
1538*8d67ca89SAndroid Build Coastguard Worker        """Return all the blocks parsed."""
1539*8d67ca89SAndroid Build Coastguard Worker
1540*8d67ca89SAndroid Build Coastguard Worker        def consume_extent(i, tokens, extent=None, detect_change=False):
1541*8d67ca89SAndroid Build Coastguard Worker            """Return tokens that belong to the given extent.
1542*8d67ca89SAndroid Build Coastguard Worker
1543*8d67ca89SAndroid Build Coastguard Worker            It parses all the tokens that follow tokens[i], until getting out
1544*8d67ca89SAndroid Build Coastguard Worker            of the extent. When detect_change is True, it may terminate early
1545*8d67ca89SAndroid Build Coastguard Worker            when detecting preprocessing directives inside the extent.
1546*8d67ca89SAndroid Build Coastguard Worker            """
1547*8d67ca89SAndroid Build Coastguard Worker
1548*8d67ca89SAndroid Build Coastguard Worker            result = []
1549*8d67ca89SAndroid Build Coastguard Worker            if extent is None:
1550*8d67ca89SAndroid Build Coastguard Worker                extent = tokens[i].cursor.extent
1551*8d67ca89SAndroid Build Coastguard Worker
1552*8d67ca89SAndroid Build Coastguard Worker            while i < len(tokens) and tokens[i].location in extent:
1553*8d67ca89SAndroid Build Coastguard Worker                t = tokens[i]
1554*8d67ca89SAndroid Build Coastguard Worker                if debugBlockParser:
1555*8d67ca89SAndroid Build Coastguard Worker                    print(' ' * 2, t.id, t.kind, t.cursor.kind)
1556*8d67ca89SAndroid Build Coastguard Worker                if (detect_change and t.cursor.extent != extent and
1557*8d67ca89SAndroid Build Coastguard Worker                    t.cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE):
1558*8d67ca89SAndroid Build Coastguard Worker                    break
1559*8d67ca89SAndroid Build Coastguard Worker                result.append(t)
1560*8d67ca89SAndroid Build Coastguard Worker                i += 1
1561*8d67ca89SAndroid Build Coastguard Worker            return (i, result)
1562*8d67ca89SAndroid Build Coastguard Worker
1563*8d67ca89SAndroid Build Coastguard Worker        def consume_line(i, tokens):
1564*8d67ca89SAndroid Build Coastguard Worker            """Return tokens that follow tokens[i] in the same line."""
1565*8d67ca89SAndroid Build Coastguard Worker            result = []
1566*8d67ca89SAndroid Build Coastguard Worker            line = tokens[i].location.line
1567*8d67ca89SAndroid Build Coastguard Worker            while i < len(tokens) and tokens[i].location.line == line:
1568*8d67ca89SAndroid Build Coastguard Worker                if tokens[i].cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE:
1569*8d67ca89SAndroid Build Coastguard Worker                    break
1570*8d67ca89SAndroid Build Coastguard Worker                result.append(tokens[i])
1571*8d67ca89SAndroid Build Coastguard Worker                i += 1
1572*8d67ca89SAndroid Build Coastguard Worker            return (i, result)
1573*8d67ca89SAndroid Build Coastguard Worker
1574*8d67ca89SAndroid Build Coastguard Worker        if tokzer is None:
1575*8d67ca89SAndroid Build Coastguard Worker            tokzer = self._tokzer
1576*8d67ca89SAndroid Build Coastguard Worker        tokens = tokzer.tokens
1577*8d67ca89SAndroid Build Coastguard Worker
1578*8d67ca89SAndroid Build Coastguard Worker        blocks = []
1579*8d67ca89SAndroid Build Coastguard Worker        buf = []
1580*8d67ca89SAndroid Build Coastguard Worker        i = 0
1581*8d67ca89SAndroid Build Coastguard Worker
1582*8d67ca89SAndroid Build Coastguard Worker        while i < len(tokens):
1583*8d67ca89SAndroid Build Coastguard Worker            t = tokens[i]
1584*8d67ca89SAndroid Build Coastguard Worker            cursor = t.cursor
1585*8d67ca89SAndroid Build Coastguard Worker
1586*8d67ca89SAndroid Build Coastguard Worker            if debugBlockParser:
1587*8d67ca89SAndroid Build Coastguard Worker                print ("%d: Processing [%s], kind=[%s], cursor=[%s], "
1588*8d67ca89SAndroid Build Coastguard Worker                       "extent=[%s]" % (t.location.line, t.spelling, t.kind,
1589*8d67ca89SAndroid Build Coastguard Worker                                        cursor.kind,
1590*8d67ca89SAndroid Build Coastguard Worker                                        self._short_extent(cursor.extent)))
1591*8d67ca89SAndroid Build Coastguard Worker
1592*8d67ca89SAndroid Build Coastguard Worker            if cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE:
1593*8d67ca89SAndroid Build Coastguard Worker                if buf:
1594*8d67ca89SAndroid Build Coastguard Worker                    blocks.append(Block(buf))
1595*8d67ca89SAndroid Build Coastguard Worker                    buf = []
1596*8d67ca89SAndroid Build Coastguard Worker
1597*8d67ca89SAndroid Build Coastguard Worker                j = i
1598*8d67ca89SAndroid Build Coastguard Worker                if j + 1 >= len(tokens):
1599*8d67ca89SAndroid Build Coastguard Worker                    raise BadExpectedToken("### BAD TOKEN at %s" % (t.location))
1600*8d67ca89SAndroid Build Coastguard Worker                directive = tokens[j+1].id
1601*8d67ca89SAndroid Build Coastguard Worker
1602*8d67ca89SAndroid Build Coastguard Worker                if directive == 'define':
1603*8d67ca89SAndroid Build Coastguard Worker                    if i+2 >= len(tokens):
1604*8d67ca89SAndroid Build Coastguard Worker                        raise BadExpectedToken("### BAD TOKEN at %s" %
1605*8d67ca89SAndroid Build Coastguard Worker                                               (tokens[i].location))
1606*8d67ca89SAndroid Build Coastguard Worker
1607*8d67ca89SAndroid Build Coastguard Worker                    # Skip '#' and 'define'.
1608*8d67ca89SAndroid Build Coastguard Worker                    extent = tokens[i].cursor.extent
1609*8d67ca89SAndroid Build Coastguard Worker                    i += 2
1610*8d67ca89SAndroid Build Coastguard Worker                    id = ''
1611*8d67ca89SAndroid Build Coastguard Worker                    # We need to separate the id from the remaining of
1612*8d67ca89SAndroid Build Coastguard Worker                    # the line, especially for the function-like macro.
1613*8d67ca89SAndroid Build Coastguard Worker                    if (i + 1 < len(tokens) and tokens[i+1].id == '(' and
1614*8d67ca89SAndroid Build Coastguard Worker                        (tokens[i].location.column + len(tokens[i].spelling) ==
1615*8d67ca89SAndroid Build Coastguard Worker                         tokens[i+1].location.column)):
1616*8d67ca89SAndroid Build Coastguard Worker                        while i < len(tokens):
1617*8d67ca89SAndroid Build Coastguard Worker                            id += tokens[i].id
1618*8d67ca89SAndroid Build Coastguard Worker                            if tokens[i].spelling == ')':
1619*8d67ca89SAndroid Build Coastguard Worker                                i += 1
1620*8d67ca89SAndroid Build Coastguard Worker                                break
1621*8d67ca89SAndroid Build Coastguard Worker                            i += 1
1622*8d67ca89SAndroid Build Coastguard Worker                    else:
1623*8d67ca89SAndroid Build Coastguard Worker                        id += tokens[i].id
1624*8d67ca89SAndroid Build Coastguard Worker                        # Advance to the next token that follows the macro id
1625*8d67ca89SAndroid Build Coastguard Worker                        i += 1
1626*8d67ca89SAndroid Build Coastguard Worker
1627*8d67ca89SAndroid Build Coastguard Worker                    (i, ret) = consume_extent(i, tokens, extent=extent)
1628*8d67ca89SAndroid Build Coastguard Worker                    blocks.append(Block(ret, directive=directive,
1629*8d67ca89SAndroid Build Coastguard Worker                                        lineno=t.location.line, identifier=id))
1630*8d67ca89SAndroid Build Coastguard Worker
1631*8d67ca89SAndroid Build Coastguard Worker                else:
1632*8d67ca89SAndroid Build Coastguard Worker                    (i, ret) = consume_extent(i, tokens)
1633*8d67ca89SAndroid Build Coastguard Worker                    blocks.append(Block(ret[2:], directive=directive,
1634*8d67ca89SAndroid Build Coastguard Worker                                        lineno=t.location.line))
1635*8d67ca89SAndroid Build Coastguard Worker
1636*8d67ca89SAndroid Build Coastguard Worker            elif cursor.kind == CursorKind.INCLUSION_DIRECTIVE:
1637*8d67ca89SAndroid Build Coastguard Worker                if buf:
1638*8d67ca89SAndroid Build Coastguard Worker                    blocks.append(Block(buf))
1639*8d67ca89SAndroid Build Coastguard Worker                    buf = []
1640*8d67ca89SAndroid Build Coastguard Worker                directive = tokens[i+1].id
1641*8d67ca89SAndroid Build Coastguard Worker                (i, ret) = consume_extent(i, tokens)
1642*8d67ca89SAndroid Build Coastguard Worker
1643*8d67ca89SAndroid Build Coastguard Worker                blocks.append(Block(ret[2:], directive=directive,
1644*8d67ca89SAndroid Build Coastguard Worker                                    lineno=t.location.line))
1645*8d67ca89SAndroid Build Coastguard Worker
1646*8d67ca89SAndroid Build Coastguard Worker            elif cursor.kind == CursorKind.VAR_DECL:
1647*8d67ca89SAndroid Build Coastguard Worker                if buf:
1648*8d67ca89SAndroid Build Coastguard Worker                    blocks.append(Block(buf))
1649*8d67ca89SAndroid Build Coastguard Worker                    buf = []
1650*8d67ca89SAndroid Build Coastguard Worker
1651*8d67ca89SAndroid Build Coastguard Worker                (i, ret) = consume_extent(i, tokens, detect_change=True)
1652*8d67ca89SAndroid Build Coastguard Worker                buf += ret
1653*8d67ca89SAndroid Build Coastguard Worker
1654*8d67ca89SAndroid Build Coastguard Worker            elif cursor.kind == CursorKind.FUNCTION_DECL:
1655*8d67ca89SAndroid Build Coastguard Worker                if buf:
1656*8d67ca89SAndroid Build Coastguard Worker                    blocks.append(Block(buf))
1657*8d67ca89SAndroid Build Coastguard Worker                    buf = []
1658*8d67ca89SAndroid Build Coastguard Worker
1659*8d67ca89SAndroid Build Coastguard Worker                (i, ret) = consume_extent(i, tokens, detect_change=True)
1660*8d67ca89SAndroid Build Coastguard Worker                buf += ret
1661*8d67ca89SAndroid Build Coastguard Worker
1662*8d67ca89SAndroid Build Coastguard Worker            else:
1663*8d67ca89SAndroid Build Coastguard Worker                (i, ret) = consume_line(i, tokens)
1664*8d67ca89SAndroid Build Coastguard Worker                buf += ret
1665*8d67ca89SAndroid Build Coastguard Worker
1666*8d67ca89SAndroid Build Coastguard Worker        if buf:
1667*8d67ca89SAndroid Build Coastguard Worker            blocks.append(Block(buf))
1668*8d67ca89SAndroid Build Coastguard Worker
1669*8d67ca89SAndroid Build Coastguard Worker        # _parsed=True indicates a successful parsing, although may result an
1670*8d67ca89SAndroid Build Coastguard Worker        # empty BlockList.
1671*8d67ca89SAndroid Build Coastguard Worker        self._parsed = True
1672*8d67ca89SAndroid Build Coastguard Worker
1673*8d67ca89SAndroid Build Coastguard Worker        return BlockList(blocks)
1674*8d67ca89SAndroid Build Coastguard Worker
1675*8d67ca89SAndroid Build Coastguard Worker    def parse(self, tokzer):
1676*8d67ca89SAndroid Build Coastguard Worker        return self.getBlocks(tokzer)
1677*8d67ca89SAndroid Build Coastguard Worker
1678*8d67ca89SAndroid Build Coastguard Worker    def parseFile(self, path):
1679*8d67ca89SAndroid Build Coastguard Worker        return self.getBlocks(CppFileTokenizer(path))
1680*8d67ca89SAndroid Build Coastguard Worker
1681*8d67ca89SAndroid Build Coastguard Worker
1682*8d67ca89SAndroid Build Coastguard Workerclass BlockParserTests(unittest.TestCase):
1683*8d67ca89SAndroid Build Coastguard Worker    """BlockParser unit tests."""
1684*8d67ca89SAndroid Build Coastguard Worker
1685*8d67ca89SAndroid Build Coastguard Worker    def get_blocks(self, lines):
1686*8d67ca89SAndroid Build Coastguard Worker        blocks = BlockParser().parse(CppStringTokenizer('\n'.join(lines)))
1687*8d67ca89SAndroid Build Coastguard Worker        return list(map(lambda a: str(a), blocks))
1688*8d67ca89SAndroid Build Coastguard Worker
1689*8d67ca89SAndroid Build Coastguard Worker    def test_hash(self):
1690*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_blocks(["#error hello"]), ["#error hello"])
1691*8d67ca89SAndroid Build Coastguard Worker
1692*8d67ca89SAndroid Build Coastguard Worker    def test_empty_line(self):
1693*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_blocks(["foo", "", "bar"]), ["foo bar"])
1694*8d67ca89SAndroid Build Coastguard Worker
1695*8d67ca89SAndroid Build Coastguard Worker    def test_hash_with_space(self):
1696*8d67ca89SAndroid Build Coastguard Worker        # We currently cannot handle the following case with libclang properly.
1697*8d67ca89SAndroid Build Coastguard Worker        # Fortunately it doesn't appear in current headers.
1698*8d67ca89SAndroid Build Coastguard Worker        #self.assertEqual(self.get_blocks(["foo", "  #  ", "bar"]), ["foo", "bar"])
1699*8d67ca89SAndroid Build Coastguard Worker        pass
1700*8d67ca89SAndroid Build Coastguard Worker
1701*8d67ca89SAndroid Build Coastguard Worker    def test_with_comment(self):
1702*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.get_blocks(["foo",
1703*8d67ca89SAndroid Build Coastguard Worker                                          "  #  /* ahah */ if defined(__KERNEL__) /* more */",
1704*8d67ca89SAndroid Build Coastguard Worker                                          "bar", "#endif"]),
1705*8d67ca89SAndroid Build Coastguard Worker                         ["foo", "#ifdef __KERNEL__", "bar", "#endif"])
1706*8d67ca89SAndroid Build Coastguard Worker
1707*8d67ca89SAndroid Build Coastguard Worker
1708*8d67ca89SAndroid Build Coastguard Worker################################################################################
1709*8d67ca89SAndroid Build Coastguard Worker################################################################################
1710*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
1711*8d67ca89SAndroid Build Coastguard Worker#####        B L O C K   L I S T   O P T I M I Z A T I O N                 #####
1712*8d67ca89SAndroid Build Coastguard Worker#####                                                                      #####
1713*8d67ca89SAndroid Build Coastguard Worker################################################################################
1714*8d67ca89SAndroid Build Coastguard Worker################################################################################
1715*8d67ca89SAndroid Build Coastguard Worker
1716*8d67ca89SAndroid Build Coastguard Worker
1717*8d67ca89SAndroid Build Coastguard Workerdef find_matching_endif(blocks, i):
1718*8d67ca89SAndroid Build Coastguard Worker    """Traverse the blocks to find out the matching #endif."""
1719*8d67ca89SAndroid Build Coastguard Worker    n = len(blocks)
1720*8d67ca89SAndroid Build Coastguard Worker    depth = 1
1721*8d67ca89SAndroid Build Coastguard Worker    while i < n:
1722*8d67ca89SAndroid Build Coastguard Worker        if blocks[i].isDirective():
1723*8d67ca89SAndroid Build Coastguard Worker            dir_ = blocks[i].directive
1724*8d67ca89SAndroid Build Coastguard Worker            if dir_ in ["if", "ifndef", "ifdef"]:
1725*8d67ca89SAndroid Build Coastguard Worker                depth += 1
1726*8d67ca89SAndroid Build Coastguard Worker            elif depth == 1 and dir_ in ["else", "elif"]:
1727*8d67ca89SAndroid Build Coastguard Worker                return i
1728*8d67ca89SAndroid Build Coastguard Worker            elif dir_ == "endif":
1729*8d67ca89SAndroid Build Coastguard Worker                depth -= 1
1730*8d67ca89SAndroid Build Coastguard Worker                if depth == 0:
1731*8d67ca89SAndroid Build Coastguard Worker                    return i
1732*8d67ca89SAndroid Build Coastguard Worker        i += 1
1733*8d67ca89SAndroid Build Coastguard Worker    return i
1734*8d67ca89SAndroid Build Coastguard Worker
1735*8d67ca89SAndroid Build Coastguard Worker
1736*8d67ca89SAndroid Build Coastguard Workerdef optimize_if01(blocks):
1737*8d67ca89SAndroid Build Coastguard Worker    """Remove the code between #if 0 .. #endif in a list of CppBlocks."""
1738*8d67ca89SAndroid Build Coastguard Worker    i = 0
1739*8d67ca89SAndroid Build Coastguard Worker    n = len(blocks)
1740*8d67ca89SAndroid Build Coastguard Worker    result = []
1741*8d67ca89SAndroid Build Coastguard Worker    while i < n:
1742*8d67ca89SAndroid Build Coastguard Worker        j = i
1743*8d67ca89SAndroid Build Coastguard Worker        while j < n and not blocks[j].isIf():
1744*8d67ca89SAndroid Build Coastguard Worker            j += 1
1745*8d67ca89SAndroid Build Coastguard Worker        if j > i:
1746*8d67ca89SAndroid Build Coastguard Worker            logging.debug("appending lines %d to %d", blocks[i].lineno,
1747*8d67ca89SAndroid Build Coastguard Worker                          blocks[j-1].lineno)
1748*8d67ca89SAndroid Build Coastguard Worker            result += blocks[i:j]
1749*8d67ca89SAndroid Build Coastguard Worker        if j >= n:
1750*8d67ca89SAndroid Build Coastguard Worker            break
1751*8d67ca89SAndroid Build Coastguard Worker        expr = blocks[j].expr
1752*8d67ca89SAndroid Build Coastguard Worker        r = expr.toInt()
1753*8d67ca89SAndroid Build Coastguard Worker        if r is None:
1754*8d67ca89SAndroid Build Coastguard Worker            result.append(blocks[j])
1755*8d67ca89SAndroid Build Coastguard Worker            i = j + 1
1756*8d67ca89SAndroid Build Coastguard Worker            continue
1757*8d67ca89SAndroid Build Coastguard Worker
1758*8d67ca89SAndroid Build Coastguard Worker        if r == 0:
1759*8d67ca89SAndroid Build Coastguard Worker            # if 0 => skip everything until the corresponding #endif
1760*8d67ca89SAndroid Build Coastguard Worker            start_dir = blocks[j].directive
1761*8d67ca89SAndroid Build Coastguard Worker            j = find_matching_endif(blocks, j + 1)
1762*8d67ca89SAndroid Build Coastguard Worker            if j >= n:
1763*8d67ca89SAndroid Build Coastguard Worker                # unterminated #if 0, finish here
1764*8d67ca89SAndroid Build Coastguard Worker                break
1765*8d67ca89SAndroid Build Coastguard Worker            dir_ = blocks[j].directive
1766*8d67ca89SAndroid Build Coastguard Worker            if dir_ == "endif":
1767*8d67ca89SAndroid Build Coastguard Worker                logging.debug("remove 'if 0' .. 'endif' (lines %d to %d)",
1768*8d67ca89SAndroid Build Coastguard Worker                              blocks[i].lineno, blocks[j].lineno)
1769*8d67ca89SAndroid Build Coastguard Worker                if start_dir == "elif":
1770*8d67ca89SAndroid Build Coastguard Worker                    # Put an endif since we started with an elif.
1771*8d67ca89SAndroid Build Coastguard Worker                    result += blocks[j:j+1]
1772*8d67ca89SAndroid Build Coastguard Worker                i = j + 1
1773*8d67ca89SAndroid Build Coastguard Worker            elif dir_ == "else":
1774*8d67ca89SAndroid Build Coastguard Worker                # convert 'else' into 'if 1'
1775*8d67ca89SAndroid Build Coastguard Worker                logging.debug("convert 'if 0' .. 'else' into 'if 1' (lines %d "
1776*8d67ca89SAndroid Build Coastguard Worker                              "to %d)", blocks[i].lineno, blocks[j-1].lineno)
1777*8d67ca89SAndroid Build Coastguard Worker                if start_dir == "elif":
1778*8d67ca89SAndroid Build Coastguard Worker                    blocks[j].directive = "elif"
1779*8d67ca89SAndroid Build Coastguard Worker                else:
1780*8d67ca89SAndroid Build Coastguard Worker                    blocks[j].directive = "if"
1781*8d67ca89SAndroid Build Coastguard Worker                blocks[j].expr = CppExpr(CppStringTokenizer("1").tokens)
1782*8d67ca89SAndroid Build Coastguard Worker                i = j
1783*8d67ca89SAndroid Build Coastguard Worker            elif dir_ == "elif":
1784*8d67ca89SAndroid Build Coastguard Worker                # convert 'elif' into 'if'
1785*8d67ca89SAndroid Build Coastguard Worker                logging.debug("convert 'if 0' .. 'elif' into 'if'")
1786*8d67ca89SAndroid Build Coastguard Worker                if start_dir == "elif":
1787*8d67ca89SAndroid Build Coastguard Worker                    blocks[j].directive = "elif"
1788*8d67ca89SAndroid Build Coastguard Worker                else:
1789*8d67ca89SAndroid Build Coastguard Worker                    blocks[j].directive = "if"
1790*8d67ca89SAndroid Build Coastguard Worker                i = j
1791*8d67ca89SAndroid Build Coastguard Worker            continue
1792*8d67ca89SAndroid Build Coastguard Worker
1793*8d67ca89SAndroid Build Coastguard Worker        # if 1 => find corresponding endif and remove/transform them
1794*8d67ca89SAndroid Build Coastguard Worker        k = find_matching_endif(blocks, j + 1)
1795*8d67ca89SAndroid Build Coastguard Worker        if k >= n:
1796*8d67ca89SAndroid Build Coastguard Worker            # unterminated #if 1, finish here
1797*8d67ca89SAndroid Build Coastguard Worker            logging.debug("unterminated 'if 1'")
1798*8d67ca89SAndroid Build Coastguard Worker            result += blocks[j+1:k]
1799*8d67ca89SAndroid Build Coastguard Worker            break
1800*8d67ca89SAndroid Build Coastguard Worker
1801*8d67ca89SAndroid Build Coastguard Worker        start_dir = blocks[j].directive
1802*8d67ca89SAndroid Build Coastguard Worker        dir_ = blocks[k].directive
1803*8d67ca89SAndroid Build Coastguard Worker        if dir_ == "endif":
1804*8d67ca89SAndroid Build Coastguard Worker            logging.debug("convert 'if 1' .. 'endif' (lines %d to %d)",
1805*8d67ca89SAndroid Build Coastguard Worker                          blocks[j].lineno, blocks[k].lineno)
1806*8d67ca89SAndroid Build Coastguard Worker            if start_dir == "elif":
1807*8d67ca89SAndroid Build Coastguard Worker                # Add the elif in to the results and convert it to an elif 1.
1808*8d67ca89SAndroid Build Coastguard Worker                blocks[j].tokens = CppStringTokenizer("1").tokens
1809*8d67ca89SAndroid Build Coastguard Worker                result += blocks[j:j+1]
1810*8d67ca89SAndroid Build Coastguard Worker            result += optimize_if01(blocks[j+1:k])
1811*8d67ca89SAndroid Build Coastguard Worker            if start_dir == "elif":
1812*8d67ca89SAndroid Build Coastguard Worker                # Add the endif in to the results.
1813*8d67ca89SAndroid Build Coastguard Worker                result += blocks[k:k+1]
1814*8d67ca89SAndroid Build Coastguard Worker            i = k + 1
1815*8d67ca89SAndroid Build Coastguard Worker        elif dir_ == "else":
1816*8d67ca89SAndroid Build Coastguard Worker            # convert 'else' into 'if 0'
1817*8d67ca89SAndroid Build Coastguard Worker            logging.debug("convert 'if 1' .. 'else' (lines %d to %d)",
1818*8d67ca89SAndroid Build Coastguard Worker                          blocks[j].lineno, blocks[k].lineno)
1819*8d67ca89SAndroid Build Coastguard Worker            if start_dir == "elif":
1820*8d67ca89SAndroid Build Coastguard Worker                # Add the elif in to the results and convert it to an elif 1.
1821*8d67ca89SAndroid Build Coastguard Worker                blocks[j].tokens = CppStringTokenizer("1").tokens
1822*8d67ca89SAndroid Build Coastguard Worker                result += blocks[j:j+1]
1823*8d67ca89SAndroid Build Coastguard Worker            result += optimize_if01(blocks[j+1:k])
1824*8d67ca89SAndroid Build Coastguard Worker            if start_dir == "elif":
1825*8d67ca89SAndroid Build Coastguard Worker                blocks[k].directive = "elif"
1826*8d67ca89SAndroid Build Coastguard Worker            else:
1827*8d67ca89SAndroid Build Coastguard Worker                blocks[k].directive = "if"
1828*8d67ca89SAndroid Build Coastguard Worker            blocks[k].expr = CppExpr(CppStringTokenizer("0").tokens)
1829*8d67ca89SAndroid Build Coastguard Worker            i = k
1830*8d67ca89SAndroid Build Coastguard Worker        elif dir_ == "elif":
1831*8d67ca89SAndroid Build Coastguard Worker            # convert 'elif' into 'if 0'
1832*8d67ca89SAndroid Build Coastguard Worker            logging.debug("convert 'if 1' .. 'elif' (lines %d to %d)",
1833*8d67ca89SAndroid Build Coastguard Worker                          blocks[j].lineno, blocks[k].lineno)
1834*8d67ca89SAndroid Build Coastguard Worker            result += optimize_if01(blocks[j+1:k])
1835*8d67ca89SAndroid Build Coastguard Worker            blocks[k].expr = CppExpr(CppStringTokenizer("0").tokens)
1836*8d67ca89SAndroid Build Coastguard Worker            i = k
1837*8d67ca89SAndroid Build Coastguard Worker    return result
1838*8d67ca89SAndroid Build Coastguard Worker
1839*8d67ca89SAndroid Build Coastguard Workerclass OptimizerTests(unittest.TestCase):
1840*8d67ca89SAndroid Build Coastguard Worker    def parse(self, text, macros=None):
1841*8d67ca89SAndroid Build Coastguard Worker        out = utils.StringOutput()
1842*8d67ca89SAndroid Build Coastguard Worker        blocks = BlockParser().parse(CppStringTokenizer(text))
1843*8d67ca89SAndroid Build Coastguard Worker        blocks.optimizeAll(macros)
1844*8d67ca89SAndroid Build Coastguard Worker        blocks.write(out)
1845*8d67ca89SAndroid Build Coastguard Worker        return out.get()
1846*8d67ca89SAndroid Build Coastguard Worker
1847*8d67ca89SAndroid Build Coastguard Worker    def test_if1(self):
1848*8d67ca89SAndroid Build Coastguard Worker        text = """\
1849*8d67ca89SAndroid Build Coastguard Worker#if 1
1850*8d67ca89SAndroid Build Coastguard Worker#define  GOOD
1851*8d67ca89SAndroid Build Coastguard Worker#endif
1852*8d67ca89SAndroid Build Coastguard Worker"""
1853*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1854*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1855*8d67ca89SAndroid Build Coastguard Worker"""
1856*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
1857*8d67ca89SAndroid Build Coastguard Worker
1858*8d67ca89SAndroid Build Coastguard Worker    def test_if0(self):
1859*8d67ca89SAndroid Build Coastguard Worker        text = """\
1860*8d67ca89SAndroid Build Coastguard Worker#if 0
1861*8d67ca89SAndroid Build Coastguard Worker#define  SHOULD_SKIP1
1862*8d67ca89SAndroid Build Coastguard Worker#define  SHOULD_SKIP2
1863*8d67ca89SAndroid Build Coastguard Worker#endif
1864*8d67ca89SAndroid Build Coastguard Worker"""
1865*8d67ca89SAndroid Build Coastguard Worker        expected = ""
1866*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
1867*8d67ca89SAndroid Build Coastguard Worker
1868*8d67ca89SAndroid Build Coastguard Worker    def test_if1_else(self):
1869*8d67ca89SAndroid Build Coastguard Worker        text = """\
1870*8d67ca89SAndroid Build Coastguard Worker#if 1
1871*8d67ca89SAndroid Build Coastguard Worker#define  GOOD
1872*8d67ca89SAndroid Build Coastguard Worker#else
1873*8d67ca89SAndroid Build Coastguard Worker#define  BAD
1874*8d67ca89SAndroid Build Coastguard Worker#endif
1875*8d67ca89SAndroid Build Coastguard Worker"""
1876*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1877*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1878*8d67ca89SAndroid Build Coastguard Worker"""
1879*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
1880*8d67ca89SAndroid Build Coastguard Worker
1881*8d67ca89SAndroid Build Coastguard Worker    def test_if0_else(self):
1882*8d67ca89SAndroid Build Coastguard Worker        text = """\
1883*8d67ca89SAndroid Build Coastguard Worker#if 0
1884*8d67ca89SAndroid Build Coastguard Worker#define  BAD
1885*8d67ca89SAndroid Build Coastguard Worker#else
1886*8d67ca89SAndroid Build Coastguard Worker#define  GOOD
1887*8d67ca89SAndroid Build Coastguard Worker#endif
1888*8d67ca89SAndroid Build Coastguard Worker"""
1889*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1890*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1891*8d67ca89SAndroid Build Coastguard Worker"""
1892*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
1893*8d67ca89SAndroid Build Coastguard Worker
1894*8d67ca89SAndroid Build Coastguard Worker    def test_if_elif1(self):
1895*8d67ca89SAndroid Build Coastguard Worker        text = """\
1896*8d67ca89SAndroid Build Coastguard Worker#if defined(something)
1897*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1898*8d67ca89SAndroid Build Coastguard Worker#elif 1
1899*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1900*8d67ca89SAndroid Build Coastguard Worker#endif
1901*8d67ca89SAndroid Build Coastguard Worker"""
1902*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1903*8d67ca89SAndroid Build Coastguard Worker#ifdef something
1904*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1905*8d67ca89SAndroid Build Coastguard Worker#elif 1
1906*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1907*8d67ca89SAndroid Build Coastguard Worker#endif
1908*8d67ca89SAndroid Build Coastguard Worker"""
1909*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
1910*8d67ca89SAndroid Build Coastguard Worker
1911*8d67ca89SAndroid Build Coastguard Worker    def test_if_elif1_macro(self):
1912*8d67ca89SAndroid Build Coastguard Worker        text = """\
1913*8d67ca89SAndroid Build Coastguard Worker#if defined(something)
1914*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1915*8d67ca89SAndroid Build Coastguard Worker#elif defined(WILL_BE_ONE)
1916*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1917*8d67ca89SAndroid Build Coastguard Worker#endif
1918*8d67ca89SAndroid Build Coastguard Worker"""
1919*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1920*8d67ca89SAndroid Build Coastguard Worker#ifdef something
1921*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1922*8d67ca89SAndroid Build Coastguard Worker#elif 1
1923*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1924*8d67ca89SAndroid Build Coastguard Worker#endif
1925*8d67ca89SAndroid Build Coastguard Worker"""
1926*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"WILL_BE_ONE": "1"}), expected)
1927*8d67ca89SAndroid Build Coastguard Worker
1928*8d67ca89SAndroid Build Coastguard Worker
1929*8d67ca89SAndroid Build Coastguard Worker    def test_if_elif1_else(self):
1930*8d67ca89SAndroid Build Coastguard Worker        text = """\
1931*8d67ca89SAndroid Build Coastguard Worker#if defined(something)
1932*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1933*8d67ca89SAndroid Build Coastguard Worker#elif 1
1934*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1935*8d67ca89SAndroid Build Coastguard Worker#else
1936*8d67ca89SAndroid Build Coastguard Worker#define BAD
1937*8d67ca89SAndroid Build Coastguard Worker#endif
1938*8d67ca89SAndroid Build Coastguard Worker"""
1939*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1940*8d67ca89SAndroid Build Coastguard Worker#ifdef something
1941*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1942*8d67ca89SAndroid Build Coastguard Worker#elif 1
1943*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1944*8d67ca89SAndroid Build Coastguard Worker#endif
1945*8d67ca89SAndroid Build Coastguard Worker"""
1946*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
1947*8d67ca89SAndroid Build Coastguard Worker
1948*8d67ca89SAndroid Build Coastguard Worker    def test_if_elif1_else_macro(self):
1949*8d67ca89SAndroid Build Coastguard Worker        text = """\
1950*8d67ca89SAndroid Build Coastguard Worker#if defined(something)
1951*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1952*8d67ca89SAndroid Build Coastguard Worker#elif defined(WILL_BE_ONE)
1953*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1954*8d67ca89SAndroid Build Coastguard Worker#else
1955*8d67ca89SAndroid Build Coastguard Worker#define BAD
1956*8d67ca89SAndroid Build Coastguard Worker#endif
1957*8d67ca89SAndroid Build Coastguard Worker"""
1958*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1959*8d67ca89SAndroid Build Coastguard Worker#ifdef something
1960*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1961*8d67ca89SAndroid Build Coastguard Worker#elif 1
1962*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1963*8d67ca89SAndroid Build Coastguard Worker#endif
1964*8d67ca89SAndroid Build Coastguard Worker"""
1965*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"WILL_BE_ONE": "1"}), expected)
1966*8d67ca89SAndroid Build Coastguard Worker
1967*8d67ca89SAndroid Build Coastguard Worker
1968*8d67ca89SAndroid Build Coastguard Worker    def test_if_elif1_else_macro(self):
1969*8d67ca89SAndroid Build Coastguard Worker        text = """\
1970*8d67ca89SAndroid Build Coastguard Worker#if defined(something)
1971*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1972*8d67ca89SAndroid Build Coastguard Worker#elif defined(WILL_BE_ONE)
1973*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1974*8d67ca89SAndroid Build Coastguard Worker#else
1975*8d67ca89SAndroid Build Coastguard Worker#define BAD
1976*8d67ca89SAndroid Build Coastguard Worker#endif
1977*8d67ca89SAndroid Build Coastguard Worker"""
1978*8d67ca89SAndroid Build Coastguard Worker        expected = """\
1979*8d67ca89SAndroid Build Coastguard Worker#ifdef something
1980*8d67ca89SAndroid Build Coastguard Worker#define EXISTS
1981*8d67ca89SAndroid Build Coastguard Worker#elif 1
1982*8d67ca89SAndroid Build Coastguard Worker#define GOOD
1983*8d67ca89SAndroid Build Coastguard Worker#endif
1984*8d67ca89SAndroid Build Coastguard Worker"""
1985*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"WILL_BE_ONE": "1"}), expected)
1986*8d67ca89SAndroid Build Coastguard Worker
1987*8d67ca89SAndroid Build Coastguard Worker    def test_macro_set_to_undefined_single(self):
1988*8d67ca89SAndroid Build Coastguard Worker        text = """\
1989*8d67ca89SAndroid Build Coastguard Worker#if defined(__KERNEL__)
1990*8d67ca89SAndroid Build Coastguard Worker#define BAD_KERNEL
1991*8d67ca89SAndroid Build Coastguard Worker#endif
1992*8d67ca89SAndroid Build Coastguard Worker"""
1993*8d67ca89SAndroid Build Coastguard Worker        expected = ""
1994*8d67ca89SAndroid Build Coastguard Worker        macros = {"__KERNEL__": kCppUndefinedMacro}
1995*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, macros), expected)
1996*8d67ca89SAndroid Build Coastguard Worker
1997*8d67ca89SAndroid Build Coastguard Worker    def test_macro_set_to_undefined_if(self):
1998*8d67ca89SAndroid Build Coastguard Worker        text = """\
1999*8d67ca89SAndroid Build Coastguard Worker#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
2000*8d67ca89SAndroid Build Coastguard Worker#define CHECK
2001*8d67ca89SAndroid Build Coastguard Worker#endif
2002*8d67ca89SAndroid Build Coastguard Worker"""
2003*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2004*8d67ca89SAndroid Build Coastguard Worker#if !defined(__GLIBC__) || __GLIBC__ < 2
2005*8d67ca89SAndroid Build Coastguard Worker#define CHECK
2006*8d67ca89SAndroid Build Coastguard Worker#endif
2007*8d67ca89SAndroid Build Coastguard Worker"""
2008*8d67ca89SAndroid Build Coastguard Worker        macros = {"__KERNEL__": kCppUndefinedMacro}
2009*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, macros), expected)
2010*8d67ca89SAndroid Build Coastguard Worker
2011*8d67ca89SAndroid Build Coastguard Worker    def test_endif_comment_removed(self):
2012*8d67ca89SAndroid Build Coastguard Worker        text = """\
2013*8d67ca89SAndroid Build Coastguard Worker#ifndef SIGRTMAX
2014*8d67ca89SAndroid Build Coastguard Worker#define SIGRTMAX 123
2015*8d67ca89SAndroid Build Coastguard Worker#endif /* SIGRTMAX */
2016*8d67ca89SAndroid Build Coastguard Worker"""
2017*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2018*8d67ca89SAndroid Build Coastguard Worker#ifndef SIGRTMAX
2019*8d67ca89SAndroid Build Coastguard Worker#define SIGRTMAX 123
2020*8d67ca89SAndroid Build Coastguard Worker#endif
2021*8d67ca89SAndroid Build Coastguard Worker"""
2022*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2023*8d67ca89SAndroid Build Coastguard Worker
2024*8d67ca89SAndroid Build Coastguard Worker    def test_multilevel_if0(self):
2025*8d67ca89SAndroid Build Coastguard Worker        text = """\
2026*8d67ca89SAndroid Build Coastguard Worker#if 0
2027*8d67ca89SAndroid Build Coastguard Worker#if 1
2028*8d67ca89SAndroid Build Coastguard Worker#define  BAD_6
2029*8d67ca89SAndroid Build Coastguard Worker#endif
2030*8d67ca89SAndroid Build Coastguard Worker#endif
2031*8d67ca89SAndroid Build Coastguard Worker"""
2032*8d67ca89SAndroid Build Coastguard Worker        expected = ""
2033*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2034*8d67ca89SAndroid Build Coastguard Worker
2035*8d67ca89SAndroid Build Coastguard Workerclass RemoveStructsTests(unittest.TestCase):
2036*8d67ca89SAndroid Build Coastguard Worker    def parse(self, text, structs):
2037*8d67ca89SAndroid Build Coastguard Worker        out = utils.StringOutput()
2038*8d67ca89SAndroid Build Coastguard Worker        blocks = BlockParser().parse(CppStringTokenizer(text))
2039*8d67ca89SAndroid Build Coastguard Worker        blocks.removeStructs(structs)
2040*8d67ca89SAndroid Build Coastguard Worker        blocks.write(out)
2041*8d67ca89SAndroid Build Coastguard Worker        return out.get()
2042*8d67ca89SAndroid Build Coastguard Worker
2043*8d67ca89SAndroid Build Coastguard Worker    def test_remove_struct_from_start(self):
2044*8d67ca89SAndroid Build Coastguard Worker        text = """\
2045*8d67ca89SAndroid Build Coastguard Workerstruct remove {
2046*8d67ca89SAndroid Build Coastguard Worker  int val1;
2047*8d67ca89SAndroid Build Coastguard Worker  int val2;
2048*8d67ca89SAndroid Build Coastguard Worker};
2049*8d67ca89SAndroid Build Coastguard Workerstruct something {
2050*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2051*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2052*8d67ca89SAndroid Build Coastguard Worker};
2053*8d67ca89SAndroid Build Coastguard Worker"""
2054*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2055*8d67ca89SAndroid Build Coastguard Workerstruct something {
2056*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2057*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2058*8d67ca89SAndroid Build Coastguard Worker};
2059*8d67ca89SAndroid Build Coastguard Worker"""
2060*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove": None}), expected)
2061*8d67ca89SAndroid Build Coastguard Worker
2062*8d67ca89SAndroid Build Coastguard Worker    def test_remove_struct_from_end(self):
2063*8d67ca89SAndroid Build Coastguard Worker        text = """\
2064*8d67ca89SAndroid Build Coastguard Workerstruct something {
2065*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2066*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2067*8d67ca89SAndroid Build Coastguard Worker};
2068*8d67ca89SAndroid Build Coastguard Workerstruct remove {
2069*8d67ca89SAndroid Build Coastguard Worker  int val1;
2070*8d67ca89SAndroid Build Coastguard Worker  int val2;
2071*8d67ca89SAndroid Build Coastguard Worker};
2072*8d67ca89SAndroid Build Coastguard Worker"""
2073*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2074*8d67ca89SAndroid Build Coastguard Workerstruct something {
2075*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2076*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2077*8d67ca89SAndroid Build Coastguard Worker};
2078*8d67ca89SAndroid Build Coastguard Worker"""
2079*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove": None}), expected)
2080*8d67ca89SAndroid Build Coastguard Worker
2081*8d67ca89SAndroid Build Coastguard Worker    def test_remove_minimal_struct(self):
2082*8d67ca89SAndroid Build Coastguard Worker        text = """\
2083*8d67ca89SAndroid Build Coastguard Workerstruct remove {
2084*8d67ca89SAndroid Build Coastguard Worker};
2085*8d67ca89SAndroid Build Coastguard Worker"""
2086*8d67ca89SAndroid Build Coastguard Worker        expected = "";
2087*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove": None}), expected)
2088*8d67ca89SAndroid Build Coastguard Worker
2089*8d67ca89SAndroid Build Coastguard Worker    def test_remove_struct_with_struct_fields(self):
2090*8d67ca89SAndroid Build Coastguard Worker        text = """\
2091*8d67ca89SAndroid Build Coastguard Workerstruct something {
2092*8d67ca89SAndroid Build Coastguard Worker  struct remove val1;
2093*8d67ca89SAndroid Build Coastguard Worker  struct remove val2;
2094*8d67ca89SAndroid Build Coastguard Worker};
2095*8d67ca89SAndroid Build Coastguard Workerstruct remove {
2096*8d67ca89SAndroid Build Coastguard Worker  int val1;
2097*8d67ca89SAndroid Build Coastguard Worker  struct something val3;
2098*8d67ca89SAndroid Build Coastguard Worker  int val2;
2099*8d67ca89SAndroid Build Coastguard Worker};
2100*8d67ca89SAndroid Build Coastguard Worker"""
2101*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2102*8d67ca89SAndroid Build Coastguard Workerstruct something {
2103*8d67ca89SAndroid Build Coastguard Worker  struct remove val1;
2104*8d67ca89SAndroid Build Coastguard Worker  struct remove val2;
2105*8d67ca89SAndroid Build Coastguard Worker};
2106*8d67ca89SAndroid Build Coastguard Worker"""
2107*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove": None}), expected)
2108*8d67ca89SAndroid Build Coastguard Worker
2109*8d67ca89SAndroid Build Coastguard Worker    def test_remove_consecutive_structs(self):
2110*8d67ca89SAndroid Build Coastguard Worker        text = """\
2111*8d67ca89SAndroid Build Coastguard Workerstruct keep1 {
2112*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2113*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2114*8d67ca89SAndroid Build Coastguard Worker};
2115*8d67ca89SAndroid Build Coastguard Workerstruct remove1 {
2116*8d67ca89SAndroid Build Coastguard Worker  int val1;
2117*8d67ca89SAndroid Build Coastguard Worker  int val2;
2118*8d67ca89SAndroid Build Coastguard Worker};
2119*8d67ca89SAndroid Build Coastguard Workerstruct remove2 {
2120*8d67ca89SAndroid Build Coastguard Worker  int val1;
2121*8d67ca89SAndroid Build Coastguard Worker  int val2;
2122*8d67ca89SAndroid Build Coastguard Worker  int val3;
2123*8d67ca89SAndroid Build Coastguard Worker};
2124*8d67ca89SAndroid Build Coastguard Workerstruct keep2 {
2125*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2126*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2127*8d67ca89SAndroid Build Coastguard Worker};
2128*8d67ca89SAndroid Build Coastguard Worker"""
2129*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2130*8d67ca89SAndroid Build Coastguard Workerstruct keep1 {
2131*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2132*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2133*8d67ca89SAndroid Build Coastguard Worker};
2134*8d67ca89SAndroid Build Coastguard Workerstruct keep2 {
2135*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2136*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2137*8d67ca89SAndroid Build Coastguard Worker};
2138*8d67ca89SAndroid Build Coastguard Worker"""
2139*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove1": None, "remove2": None}), expected)
2140*8d67ca89SAndroid Build Coastguard Worker
2141*8d67ca89SAndroid Build Coastguard Worker    def test_remove_multiple_structs(self):
2142*8d67ca89SAndroid Build Coastguard Worker        text = """\
2143*8d67ca89SAndroid Build Coastguard Workerstruct keep1 {
2144*8d67ca89SAndroid Build Coastguard Worker  int val;
2145*8d67ca89SAndroid Build Coastguard Worker};
2146*8d67ca89SAndroid Build Coastguard Workerstruct remove1 {
2147*8d67ca89SAndroid Build Coastguard Worker  int val1;
2148*8d67ca89SAndroid Build Coastguard Worker  int val2;
2149*8d67ca89SAndroid Build Coastguard Worker};
2150*8d67ca89SAndroid Build Coastguard Workerstruct keep2 {
2151*8d67ca89SAndroid Build Coastguard Worker  int val;
2152*8d67ca89SAndroid Build Coastguard Worker};
2153*8d67ca89SAndroid Build Coastguard Workerstruct remove2 {
2154*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2155*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2156*8d67ca89SAndroid Build Coastguard Worker};
2157*8d67ca89SAndroid Build Coastguard Workerstruct keep3 {
2158*8d67ca89SAndroid Build Coastguard Worker  int val;
2159*8d67ca89SAndroid Build Coastguard Worker};
2160*8d67ca89SAndroid Build Coastguard Worker"""
2161*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2162*8d67ca89SAndroid Build Coastguard Workerstruct keep1 {
2163*8d67ca89SAndroid Build Coastguard Worker  int val;
2164*8d67ca89SAndroid Build Coastguard Worker};
2165*8d67ca89SAndroid Build Coastguard Workerstruct keep2 {
2166*8d67ca89SAndroid Build Coastguard Worker  int val;
2167*8d67ca89SAndroid Build Coastguard Worker};
2168*8d67ca89SAndroid Build Coastguard Workerstruct keep3 {
2169*8d67ca89SAndroid Build Coastguard Worker  int val;
2170*8d67ca89SAndroid Build Coastguard Worker};
2171*8d67ca89SAndroid Build Coastguard Worker"""
2172*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove1": None, "remove2": None}), expected)
2173*8d67ca89SAndroid Build Coastguard Worker
2174*8d67ca89SAndroid Build Coastguard Worker    def test_remove_struct_with_inline_structs(self):
2175*8d67ca89SAndroid Build Coastguard Worker        text = """\
2176*8d67ca89SAndroid Build Coastguard Workerstruct remove {
2177*8d67ca89SAndroid Build Coastguard Worker  int val1;
2178*8d67ca89SAndroid Build Coastguard Worker  int val2;
2179*8d67ca89SAndroid Build Coastguard Worker  struct {
2180*8d67ca89SAndroid Build Coastguard Worker    int val1;
2181*8d67ca89SAndroid Build Coastguard Worker    struct {
2182*8d67ca89SAndroid Build Coastguard Worker      int val1;
2183*8d67ca89SAndroid Build Coastguard Worker    } level2;
2184*8d67ca89SAndroid Build Coastguard Worker  } level1;
2185*8d67ca89SAndroid Build Coastguard Worker};
2186*8d67ca89SAndroid Build Coastguard Workerstruct something {
2187*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2188*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2189*8d67ca89SAndroid Build Coastguard Worker};
2190*8d67ca89SAndroid Build Coastguard Worker"""
2191*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2192*8d67ca89SAndroid Build Coastguard Workerstruct something {
2193*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2194*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2195*8d67ca89SAndroid Build Coastguard Worker};
2196*8d67ca89SAndroid Build Coastguard Worker"""
2197*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove": None}), expected)
2198*8d67ca89SAndroid Build Coastguard Worker
2199*8d67ca89SAndroid Build Coastguard Worker    def test_remove_struct_across_blocks(self):
2200*8d67ca89SAndroid Build Coastguard Worker        text = """\
2201*8d67ca89SAndroid Build Coastguard Workerstruct remove {
2202*8d67ca89SAndroid Build Coastguard Worker  int val1;
2203*8d67ca89SAndroid Build Coastguard Worker  int val2;
2204*8d67ca89SAndroid Build Coastguard Worker#ifdef PARAMETER1
2205*8d67ca89SAndroid Build Coastguard Worker  PARAMETER1
2206*8d67ca89SAndroid Build Coastguard Worker#endif
2207*8d67ca89SAndroid Build Coastguard Worker#ifdef PARAMETER2
2208*8d67ca89SAndroid Build Coastguard Worker  PARAMETER2
2209*8d67ca89SAndroid Build Coastguard Worker#endif
2210*8d67ca89SAndroid Build Coastguard Worker};
2211*8d67ca89SAndroid Build Coastguard Workerstruct something {
2212*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2213*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2214*8d67ca89SAndroid Build Coastguard Worker};
2215*8d67ca89SAndroid Build Coastguard Worker"""
2216*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2217*8d67ca89SAndroid Build Coastguard Workerstruct something {
2218*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2219*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2220*8d67ca89SAndroid Build Coastguard Worker};
2221*8d67ca89SAndroid Build Coastguard Worker"""
2222*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove": None}), expected)
2223*8d67ca89SAndroid Build Coastguard Worker
2224*8d67ca89SAndroid Build Coastguard Worker    def test_remove_struct_across_blocks_multiple_structs(self):
2225*8d67ca89SAndroid Build Coastguard Worker        text = """\
2226*8d67ca89SAndroid Build Coastguard Workerstruct remove1 {
2227*8d67ca89SAndroid Build Coastguard Worker  int val1;
2228*8d67ca89SAndroid Build Coastguard Worker  int val2;
2229*8d67ca89SAndroid Build Coastguard Worker#ifdef PARAMETER1
2230*8d67ca89SAndroid Build Coastguard Worker  PARAMETER1
2231*8d67ca89SAndroid Build Coastguard Worker#endif
2232*8d67ca89SAndroid Build Coastguard Worker#ifdef PARAMETER2
2233*8d67ca89SAndroid Build Coastguard Worker  PARAMETER2
2234*8d67ca89SAndroid Build Coastguard Worker#endif
2235*8d67ca89SAndroid Build Coastguard Worker};
2236*8d67ca89SAndroid Build Coastguard Workerstruct remove2 {
2237*8d67ca89SAndroid Build Coastguard Worker};
2238*8d67ca89SAndroid Build Coastguard Workerstruct something {
2239*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2240*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2241*8d67ca89SAndroid Build Coastguard Worker};
2242*8d67ca89SAndroid Build Coastguard Worker"""
2243*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2244*8d67ca89SAndroid Build Coastguard Workerstruct something {
2245*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2246*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2247*8d67ca89SAndroid Build Coastguard Worker};
2248*8d67ca89SAndroid Build Coastguard Worker"""
2249*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove1": None, "remove2": None}), expected)
2250*8d67ca89SAndroid Build Coastguard Worker
2251*8d67ca89SAndroid Build Coastguard Worker    def test_remove_multiple_struct_and_add_includes(self):
2252*8d67ca89SAndroid Build Coastguard Worker        text = """\
2253*8d67ca89SAndroid Build Coastguard Workerstruct remove1 {
2254*8d67ca89SAndroid Build Coastguard Worker  int val1;
2255*8d67ca89SAndroid Build Coastguard Worker  int val2;
2256*8d67ca89SAndroid Build Coastguard Worker};
2257*8d67ca89SAndroid Build Coastguard Workerstruct remove2 {
2258*8d67ca89SAndroid Build Coastguard Worker  struct timeval val1;
2259*8d67ca89SAndroid Build Coastguard Worker  struct timeval val2;
2260*8d67ca89SAndroid Build Coastguard Worker};
2261*8d67ca89SAndroid Build Coastguard Worker"""
2262*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2263*8d67ca89SAndroid Build Coastguard Worker#include <bits/remove1.h>
2264*8d67ca89SAndroid Build Coastguard Worker#include <bits/remove2.h>
2265*8d67ca89SAndroid Build Coastguard Worker"""
2266*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, {"remove1": "bits/remove1.h", "remove2": "bits/remove2.h"}), expected)
2267*8d67ca89SAndroid Build Coastguard Worker
2268*8d67ca89SAndroid Build Coastguard Worker
2269*8d67ca89SAndroid Build Coastguard Workerclass FullPathTest(unittest.TestCase):
2270*8d67ca89SAndroid Build Coastguard Worker    """Test of the full path parsing."""
2271*8d67ca89SAndroid Build Coastguard Worker
2272*8d67ca89SAndroid Build Coastguard Worker    def parse(self, text, keep=None):
2273*8d67ca89SAndroid Build Coastguard Worker        if not keep:
2274*8d67ca89SAndroid Build Coastguard Worker            keep = set()
2275*8d67ca89SAndroid Build Coastguard Worker        out = utils.StringOutput()
2276*8d67ca89SAndroid Build Coastguard Worker        blocks = BlockParser().parse(CppStringTokenizer(text))
2277*8d67ca89SAndroid Build Coastguard Worker
2278*8d67ca89SAndroid Build Coastguard Worker        blocks.removeStructs(kernel_structs_to_remove)
2279*8d67ca89SAndroid Build Coastguard Worker        blocks.removeVarsAndFuncs(keep)
2280*8d67ca89SAndroid Build Coastguard Worker        blocks.replaceTokens(kernel_token_replacements)
2281*8d67ca89SAndroid Build Coastguard Worker        blocks.optimizeAll(None)
2282*8d67ca89SAndroid Build Coastguard Worker
2283*8d67ca89SAndroid Build Coastguard Worker        blocks.write(out)
2284*8d67ca89SAndroid Build Coastguard Worker        return out.get()
2285*8d67ca89SAndroid Build Coastguard Worker
2286*8d67ca89SAndroid Build Coastguard Worker    def test_function_removed(self):
2287*8d67ca89SAndroid Build Coastguard Worker        text = """\
2288*8d67ca89SAndroid Build Coastguard Workerstatic inline __u64 function()
2289*8d67ca89SAndroid Build Coastguard Worker{
2290*8d67ca89SAndroid Build Coastguard Worker}
2291*8d67ca89SAndroid Build Coastguard Worker"""
2292*8d67ca89SAndroid Build Coastguard Worker        expected = ""
2293*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2294*8d67ca89SAndroid Build Coastguard Worker
2295*8d67ca89SAndroid Build Coastguard Worker    def test_function_removed_with_struct(self):
2296*8d67ca89SAndroid Build Coastguard Worker        text = """\
2297*8d67ca89SAndroid Build Coastguard Workerstatic inline struct something* function()
2298*8d67ca89SAndroid Build Coastguard Worker{
2299*8d67ca89SAndroid Build Coastguard Worker}
2300*8d67ca89SAndroid Build Coastguard Worker"""
2301*8d67ca89SAndroid Build Coastguard Worker        expected = ""
2302*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2303*8d67ca89SAndroid Build Coastguard Worker
2304*8d67ca89SAndroid Build Coastguard Worker    def test_function_kept(self):
2305*8d67ca89SAndroid Build Coastguard Worker        text = """\
2306*8d67ca89SAndroid Build Coastguard Workerstatic inline __u64 function()
2307*8d67ca89SAndroid Build Coastguard Worker{
2308*8d67ca89SAndroid Build Coastguard Worker}
2309*8d67ca89SAndroid Build Coastguard Worker"""
2310*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2311*8d67ca89SAndroid Build Coastguard Workerstatic inline __u64 function() {
2312*8d67ca89SAndroid Build Coastguard Worker}
2313*8d67ca89SAndroid Build Coastguard Worker"""
2314*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, set(["function"])), expected)
2315*8d67ca89SAndroid Build Coastguard Worker
2316*8d67ca89SAndroid Build Coastguard Worker    def test_var_removed(self):
2317*8d67ca89SAndroid Build Coastguard Worker        text = "__u64 variable;"
2318*8d67ca89SAndroid Build Coastguard Worker        expected = ""
2319*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2320*8d67ca89SAndroid Build Coastguard Worker
2321*8d67ca89SAndroid Build Coastguard Worker    def test_var_kept(self):
2322*8d67ca89SAndroid Build Coastguard Worker        text = "__u64 variable;"
2323*8d67ca89SAndroid Build Coastguard Worker        expected = "__u64 variable;\n"
2324*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, set(["variable"])), expected)
2325*8d67ca89SAndroid Build Coastguard Worker
2326*8d67ca89SAndroid Build Coastguard Worker    def test_keep_function_typedef(self):
2327*8d67ca89SAndroid Build Coastguard Worker        text = "typedef void somefunction_t(void);"
2328*8d67ca89SAndroid Build Coastguard Worker        expected = "typedef void somefunction_t(void);\n"
2329*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2330*8d67ca89SAndroid Build Coastguard Worker
2331*8d67ca89SAndroid Build Coastguard Worker    def test_struct_keep_attribute(self):
2332*8d67ca89SAndroid Build Coastguard Worker        text = """\
2333*8d67ca89SAndroid Build Coastguard Workerstruct something_s {
2334*8d67ca89SAndroid Build Coastguard Worker  __u32 s1;
2335*8d67ca89SAndroid Build Coastguard Worker  __u32 s2;
2336*8d67ca89SAndroid Build Coastguard Worker} __attribute__((packed));
2337*8d67ca89SAndroid Build Coastguard Worker"""
2338*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2339*8d67ca89SAndroid Build Coastguard Workerstruct something_s {
2340*8d67ca89SAndroid Build Coastguard Worker  __u32 s1;
2341*8d67ca89SAndroid Build Coastguard Worker  __u32 s2;
2342*8d67ca89SAndroid Build Coastguard Worker} __attribute__((packed));
2343*8d67ca89SAndroid Build Coastguard Worker"""
2344*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2345*8d67ca89SAndroid Build Coastguard Worker
2346*8d67ca89SAndroid Build Coastguard Worker    def test_function_keep_attribute_structs(self):
2347*8d67ca89SAndroid Build Coastguard Worker        text = """\
2348*8d67ca89SAndroid Build Coastguard Workerstatic __inline__ struct some_struct1 * function(struct some_struct2 * e) {
2349*8d67ca89SAndroid Build Coastguard Worker}
2350*8d67ca89SAndroid Build Coastguard Worker"""
2351*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2352*8d67ca89SAndroid Build Coastguard Workerstatic __inline__ struct some_struct1 * function(struct some_struct2 * e) {
2353*8d67ca89SAndroid Build Coastguard Worker}
2354*8d67ca89SAndroid Build Coastguard Worker"""
2355*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, set(["function"])), expected)
2356*8d67ca89SAndroid Build Coastguard Worker
2357*8d67ca89SAndroid Build Coastguard Worker    def test_struct_after_struct(self):
2358*8d67ca89SAndroid Build Coastguard Worker        text = """\
2359*8d67ca89SAndroid Build Coastguard Workerstruct first {
2360*8d67ca89SAndroid Build Coastguard Worker};
2361*8d67ca89SAndroid Build Coastguard Worker
2362*8d67ca89SAndroid Build Coastguard Workerstruct second {
2363*8d67ca89SAndroid Build Coastguard Worker  unsigned short s1;
2364*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING 8
2365*8d67ca89SAndroid Build Coastguard Worker  unsigned short s2;
2366*8d67ca89SAndroid Build Coastguard Worker};
2367*8d67ca89SAndroid Build Coastguard Worker"""
2368*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2369*8d67ca89SAndroid Build Coastguard Workerstruct first {
2370*8d67ca89SAndroid Build Coastguard Worker};
2371*8d67ca89SAndroid Build Coastguard Workerstruct second {
2372*8d67ca89SAndroid Build Coastguard Worker  unsigned short s1;
2373*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING 8
2374*8d67ca89SAndroid Build Coastguard Worker  unsigned short s2;
2375*8d67ca89SAndroid Build Coastguard Worker};
2376*8d67ca89SAndroid Build Coastguard Worker"""
2377*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2378*8d67ca89SAndroid Build Coastguard Worker
2379*8d67ca89SAndroid Build Coastguard Worker    def test_other_not_removed(self):
2380*8d67ca89SAndroid Build Coastguard Worker        text = """\
2381*8d67ca89SAndroid Build Coastguard Workertypedef union {
2382*8d67ca89SAndroid Build Coastguard Worker  __u64 tu1;
2383*8d67ca89SAndroid Build Coastguard Worker  __u64 tu2;
2384*8d67ca89SAndroid Build Coastguard Worker} typedef_name;
2385*8d67ca89SAndroid Build Coastguard Worker
2386*8d67ca89SAndroid Build Coastguard Workerunion {
2387*8d67ca89SAndroid Build Coastguard Worker  __u64 u1;
2388*8d67ca89SAndroid Build Coastguard Worker  __u64 u2;
2389*8d67ca89SAndroid Build Coastguard Worker};
2390*8d67ca89SAndroid Build Coastguard Worker
2391*8d67ca89SAndroid Build Coastguard Workerstruct {
2392*8d67ca89SAndroid Build Coastguard Worker  __u64 s1;
2393*8d67ca89SAndroid Build Coastguard Worker  __u64 s2;
2394*8d67ca89SAndroid Build Coastguard Worker};
2395*8d67ca89SAndroid Build Coastguard Worker
2396*8d67ca89SAndroid Build Coastguard Workerenum {
2397*8d67ca89SAndroid Build Coastguard Worker  ENUM1 = 0,
2398*8d67ca89SAndroid Build Coastguard Worker  ENUM2,
2399*8d67ca89SAndroid Build Coastguard Worker};
2400*8d67ca89SAndroid Build Coastguard Worker
2401*8d67ca89SAndroid Build Coastguard Worker__extension__ typedef __signed__ long long __s64;
2402*8d67ca89SAndroid Build Coastguard Worker"""
2403*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2404*8d67ca89SAndroid Build Coastguard Workertypedef union {
2405*8d67ca89SAndroid Build Coastguard Worker  __u64 tu1;
2406*8d67ca89SAndroid Build Coastguard Worker  __u64 tu2;
2407*8d67ca89SAndroid Build Coastguard Worker} typedef_name;
2408*8d67ca89SAndroid Build Coastguard Workerunion {
2409*8d67ca89SAndroid Build Coastguard Worker  __u64 u1;
2410*8d67ca89SAndroid Build Coastguard Worker  __u64 u2;
2411*8d67ca89SAndroid Build Coastguard Worker};
2412*8d67ca89SAndroid Build Coastguard Workerstruct {
2413*8d67ca89SAndroid Build Coastguard Worker  __u64 s1;
2414*8d67ca89SAndroid Build Coastguard Worker  __u64 s2;
2415*8d67ca89SAndroid Build Coastguard Worker};
2416*8d67ca89SAndroid Build Coastguard Workerenum {
2417*8d67ca89SAndroid Build Coastguard Worker  ENUM1 = 0,
2418*8d67ca89SAndroid Build Coastguard Worker  ENUM2,
2419*8d67ca89SAndroid Build Coastguard Worker};
2420*8d67ca89SAndroid Build Coastguard Worker__extension__ typedef __signed__ long long __s64;
2421*8d67ca89SAndroid Build Coastguard Worker"""
2422*8d67ca89SAndroid Build Coastguard Worker
2423*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2424*8d67ca89SAndroid Build Coastguard Worker
2425*8d67ca89SAndroid Build Coastguard Worker    def test_semicolon_after_function(self):
2426*8d67ca89SAndroid Build Coastguard Worker        text = """\
2427*8d67ca89SAndroid Build Coastguard Workerstatic inline __u64 function()
2428*8d67ca89SAndroid Build Coastguard Worker{
2429*8d67ca89SAndroid Build Coastguard Worker};
2430*8d67ca89SAndroid Build Coastguard Worker
2431*8d67ca89SAndroid Build Coastguard Workerstruct should_see {
2432*8d67ca89SAndroid Build Coastguard Worker        __u32                           field;
2433*8d67ca89SAndroid Build Coastguard Worker};
2434*8d67ca89SAndroid Build Coastguard Worker"""
2435*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2436*8d67ca89SAndroid Build Coastguard Workerstruct should_see {
2437*8d67ca89SAndroid Build Coastguard Worker  __u32 field;
2438*8d67ca89SAndroid Build Coastguard Worker};
2439*8d67ca89SAndroid Build Coastguard Worker"""
2440*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2441*8d67ca89SAndroid Build Coastguard Worker
2442*8d67ca89SAndroid Build Coastguard Worker    def test_define_in_middle_keep(self):
2443*8d67ca89SAndroid Build Coastguard Worker        text = """\
2444*8d67ca89SAndroid Build Coastguard Workerenum {
2445*8d67ca89SAndroid Build Coastguard Worker  ENUM0 = 0x10,
2446*8d67ca89SAndroid Build Coastguard Worker  ENUM1 = 0x20,
2447*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING SOMETHING_ELSE
2448*8d67ca89SAndroid Build Coastguard Worker  ENUM2 = 0x40,
2449*8d67ca89SAndroid Build Coastguard Worker};
2450*8d67ca89SAndroid Build Coastguard Worker"""
2451*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2452*8d67ca89SAndroid Build Coastguard Workerenum {
2453*8d67ca89SAndroid Build Coastguard Worker  ENUM0 = 0x10,
2454*8d67ca89SAndroid Build Coastguard Worker  ENUM1 = 0x20,
2455*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING SOMETHING_ELSE
2456*8d67ca89SAndroid Build Coastguard Worker  ENUM2 = 0x40,
2457*8d67ca89SAndroid Build Coastguard Worker};
2458*8d67ca89SAndroid Build Coastguard Worker"""
2459*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2460*8d67ca89SAndroid Build Coastguard Worker
2461*8d67ca89SAndroid Build Coastguard Worker    def test_define_in_middle_remove(self):
2462*8d67ca89SAndroid Build Coastguard Worker        text = """\
2463*8d67ca89SAndroid Build Coastguard Workerstatic inline function() {
2464*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING1 SOMETHING_ELSE1
2465*8d67ca89SAndroid Build Coastguard Worker  i = 0;
2466*8d67ca89SAndroid Build Coastguard Worker  {
2467*8d67ca89SAndroid Build Coastguard Worker    i = 1;
2468*8d67ca89SAndroid Build Coastguard Worker  }
2469*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING2 SOMETHING_ELSE2
2470*8d67ca89SAndroid Build Coastguard Worker}
2471*8d67ca89SAndroid Build Coastguard Worker"""
2472*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2473*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING1 SOMETHING_ELSE1
2474*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING2 SOMETHING_ELSE2
2475*8d67ca89SAndroid Build Coastguard Worker"""
2476*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2477*8d67ca89SAndroid Build Coastguard Worker
2478*8d67ca89SAndroid Build Coastguard Worker    def test_define_in_middle_force_keep(self):
2479*8d67ca89SAndroid Build Coastguard Worker        text = """\
2480*8d67ca89SAndroid Build Coastguard Workerstatic inline function() {
2481*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING1 SOMETHING_ELSE1
2482*8d67ca89SAndroid Build Coastguard Worker  i = 0;
2483*8d67ca89SAndroid Build Coastguard Worker  {
2484*8d67ca89SAndroid Build Coastguard Worker    i = 1;
2485*8d67ca89SAndroid Build Coastguard Worker  }
2486*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING2 SOMETHING_ELSE2
2487*8d67ca89SAndroid Build Coastguard Worker}
2488*8d67ca89SAndroid Build Coastguard Worker"""
2489*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2490*8d67ca89SAndroid Build Coastguard Workerstatic inline function() {
2491*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING1 SOMETHING_ELSE1
2492*8d67ca89SAndroid Build Coastguard Worker  i = 0;
2493*8d67ca89SAndroid Build Coastguard Worker {
2494*8d67ca89SAndroid Build Coastguard Worker    i = 1;
2495*8d67ca89SAndroid Build Coastguard Worker  }
2496*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING2 SOMETHING_ELSE2
2497*8d67ca89SAndroid Build Coastguard Worker}
2498*8d67ca89SAndroid Build Coastguard Worker"""
2499*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text, set(["function"])), expected)
2500*8d67ca89SAndroid Build Coastguard Worker
2501*8d67ca89SAndroid Build Coastguard Worker    def test_define_before_remove(self):
2502*8d67ca89SAndroid Build Coastguard Worker        text = """\
2503*8d67ca89SAndroid Build Coastguard Worker#define SHOULD_BE_KEPT NOTHING1
2504*8d67ca89SAndroid Build Coastguard Worker#define ANOTHER_TO_KEEP NOTHING2
2505*8d67ca89SAndroid Build Coastguard Workerstatic inline function() {
2506*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING1 SOMETHING_ELSE1
2507*8d67ca89SAndroid Build Coastguard Worker  i = 0;
2508*8d67ca89SAndroid Build Coastguard Worker  {
2509*8d67ca89SAndroid Build Coastguard Worker    i = 1;
2510*8d67ca89SAndroid Build Coastguard Worker  }
2511*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING2 SOMETHING_ELSE2
2512*8d67ca89SAndroid Build Coastguard Worker}
2513*8d67ca89SAndroid Build Coastguard Worker"""
2514*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2515*8d67ca89SAndroid Build Coastguard Worker#define SHOULD_BE_KEPT NOTHING1
2516*8d67ca89SAndroid Build Coastguard Worker#define ANOTHER_TO_KEEP NOTHING2
2517*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING1 SOMETHING_ELSE1
2518*8d67ca89SAndroid Build Coastguard Worker#define SOMETHING2 SOMETHING_ELSE2
2519*8d67ca89SAndroid Build Coastguard Worker"""
2520*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2521*8d67ca89SAndroid Build Coastguard Worker
2522*8d67ca89SAndroid Build Coastguard Worker    def test_extern_C(self):
2523*8d67ca89SAndroid Build Coastguard Worker        text = """\
2524*8d67ca89SAndroid Build Coastguard Worker#if defined(__cplusplus)
2525*8d67ca89SAndroid Build Coastguard Workerextern "C" {
2526*8d67ca89SAndroid Build Coastguard Worker#endif
2527*8d67ca89SAndroid Build Coastguard Worker
2528*8d67ca89SAndroid Build Coastguard Workerstruct something {
2529*8d67ca89SAndroid Build Coastguard Worker};
2530*8d67ca89SAndroid Build Coastguard Worker
2531*8d67ca89SAndroid Build Coastguard Worker#if defined(__cplusplus)
2532*8d67ca89SAndroid Build Coastguard Worker}
2533*8d67ca89SAndroid Build Coastguard Worker#endif
2534*8d67ca89SAndroid Build Coastguard Worker"""
2535*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2536*8d67ca89SAndroid Build Coastguard Worker#ifdef __cplusplus
2537*8d67ca89SAndroid Build Coastguard Workerextern "C" {
2538*8d67ca89SAndroid Build Coastguard Worker#endif
2539*8d67ca89SAndroid Build Coastguard Workerstruct something {
2540*8d67ca89SAndroid Build Coastguard Worker};
2541*8d67ca89SAndroid Build Coastguard Worker#ifdef __cplusplus
2542*8d67ca89SAndroid Build Coastguard Worker}
2543*8d67ca89SAndroid Build Coastguard Worker#endif
2544*8d67ca89SAndroid Build Coastguard Worker"""
2545*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2546*8d67ca89SAndroid Build Coastguard Worker
2547*8d67ca89SAndroid Build Coastguard Worker    def test_macro_definition_removed(self):
2548*8d67ca89SAndroid Build Coastguard Worker        text = """\
2549*8d67ca89SAndroid Build Coastguard Worker#define MACRO_FUNCTION_NO_PARAMS static inline some_func() {}
2550*8d67ca89SAndroid Build Coastguard WorkerMACRO_FUNCTION_NO_PARAMS()
2551*8d67ca89SAndroid Build Coastguard Worker
2552*8d67ca89SAndroid Build Coastguard Worker#define MACRO_FUNCTION_PARAMS(a) static inline some_func() { a; }
2553*8d67ca89SAndroid Build Coastguard WorkerMACRO_FUNCTION_PARAMS(a = 1)
2554*8d67ca89SAndroid Build Coastguard Worker
2555*8d67ca89SAndroid Build Coastguard Workersomething that should still be kept
2556*8d67ca89SAndroid Build Coastguard WorkerMACRO_FUNCTION_PARAMS(b)
2557*8d67ca89SAndroid Build Coastguard Worker"""
2558*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2559*8d67ca89SAndroid Build Coastguard Worker#define MACRO_FUNCTION_NO_PARAMS static inline some_func() { }
2560*8d67ca89SAndroid Build Coastguard Worker#define MACRO_FUNCTION_PARAMS(a) static inline some_func() { a; }
2561*8d67ca89SAndroid Build Coastguard Workersomething that should still be kept
2562*8d67ca89SAndroid Build Coastguard Worker"""
2563*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2564*8d67ca89SAndroid Build Coastguard Worker
2565*8d67ca89SAndroid Build Coastguard Worker    def test_verify_timeval_itemerval(self):
2566*8d67ca89SAndroid Build Coastguard Worker        text = """\
2567*8d67ca89SAndroid Build Coastguard Workerstruct __kernel_old_timeval {
2568*8d67ca89SAndroid Build Coastguard Worker  struct something val;
2569*8d67ca89SAndroid Build Coastguard Worker};
2570*8d67ca89SAndroid Build Coastguard Workerstruct __kernel_old_itimerval {
2571*8d67ca89SAndroid Build Coastguard Worker  struct __kernel_old_timeval val;
2572*8d67ca89SAndroid Build Coastguard Worker};
2573*8d67ca89SAndroid Build Coastguard Workerstruct fields {
2574*8d67ca89SAndroid Build Coastguard Worker  struct __kernel_old_timeval timeval;
2575*8d67ca89SAndroid Build Coastguard Worker  struct __kernel_old_itimerval itimerval;
2576*8d67ca89SAndroid Build Coastguard Worker};
2577*8d67ca89SAndroid Build Coastguard Worker"""
2578*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2579*8d67ca89SAndroid Build Coastguard Workerstruct fields {
2580*8d67ca89SAndroid Build Coastguard Worker  struct timeval timeval;
2581*8d67ca89SAndroid Build Coastguard Worker  struct itimerval itimerval;
2582*8d67ca89SAndroid Build Coastguard Worker};
2583*8d67ca89SAndroid Build Coastguard Worker#include <linux/time.h>
2584*8d67ca89SAndroid Build Coastguard Worker"""
2585*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2586*8d67ca89SAndroid Build Coastguard Worker
2587*8d67ca89SAndroid Build Coastguard Worker    def test_var_definition(self):
2588*8d67ca89SAndroid Build Coastguard Worker        # If we're definining the whole thing, it's probably worth keeping.
2589*8d67ca89SAndroid Build Coastguard Worker        text = """\
2590*8d67ca89SAndroid Build Coastguard Workerstatic const char *kString = "hello world";
2591*8d67ca89SAndroid Build Coastguard Workerstatic const int kInteger = 42;
2592*8d67ca89SAndroid Build Coastguard Worker"""
2593*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2594*8d67ca89SAndroid Build Coastguard Workerstatic const char * kString = "hello world";
2595*8d67ca89SAndroid Build Coastguard Workerstatic const int kInteger = 42;
2596*8d67ca89SAndroid Build Coastguard Worker"""
2597*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2598*8d67ca89SAndroid Build Coastguard Worker
2599*8d67ca89SAndroid Build Coastguard Worker    def test_struct_array_definition(self):
2600*8d67ca89SAndroid Build Coastguard Worker        text = """\
2601*8d67ca89SAndroid Build Coastguard Workerstruct descriptor {
2602*8d67ca89SAndroid Build Coastguard Worker  int args;
2603*8d67ca89SAndroid Build Coastguard Worker  int size;
2604*8d67ca89SAndroid Build Coastguard Worker};
2605*8d67ca89SAndroid Build Coastguard Workerstatic const struct descriptor[] = {
2606*8d67ca89SAndroid Build Coastguard Worker  {0, 0},
2607*8d67ca89SAndroid Build Coastguard Worker  {1, 12},
2608*8d67ca89SAndroid Build Coastguard Worker  {0, 42},
2609*8d67ca89SAndroid Build Coastguard Worker};
2610*8d67ca89SAndroid Build Coastguard Worker"""
2611*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2612*8d67ca89SAndroid Build Coastguard Workerstruct descriptor {
2613*8d67ca89SAndroid Build Coastguard Worker  int args;
2614*8d67ca89SAndroid Build Coastguard Worker  int size;
2615*8d67ca89SAndroid Build Coastguard Worker};
2616*8d67ca89SAndroid Build Coastguard Workerstatic const struct descriptor[] = {
2617*8d67ca89SAndroid Build Coastguard Worker {
2618*8d67ca89SAndroid Build Coastguard Worker    0, 0
2619*8d67ca89SAndroid Build Coastguard Worker  }
2620*8d67ca89SAndroid Build Coastguard Worker , {
2621*8d67ca89SAndroid Build Coastguard Worker    1, 12
2622*8d67ca89SAndroid Build Coastguard Worker  }
2623*8d67ca89SAndroid Build Coastguard Worker , {
2624*8d67ca89SAndroid Build Coastguard Worker    0, 42
2625*8d67ca89SAndroid Build Coastguard Worker  }
2626*8d67ca89SAndroid Build Coastguard Worker ,
2627*8d67ca89SAndroid Build Coastguard Worker};
2628*8d67ca89SAndroid Build Coastguard Worker"""
2629*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2630*8d67ca89SAndroid Build Coastguard Worker
2631*8d67ca89SAndroid Build Coastguard Worker    def test_array_definition(self):
2632*8d67ca89SAndroid Build Coastguard Worker        text = """\
2633*8d67ca89SAndroid Build Coastguard Workerstatic const char *arr[] = {
2634*8d67ca89SAndroid Build Coastguard Worker  "foo",
2635*8d67ca89SAndroid Build Coastguard Worker  "bar",
2636*8d67ca89SAndroid Build Coastguard Worker  "baz",
2637*8d67ca89SAndroid Build Coastguard Worker};
2638*8d67ca89SAndroid Build Coastguard Worker
2639*8d67ca89SAndroid Build Coastguard Workerstatic int another_arr[5] = { 1, 2, 3, 4, 5};
2640*8d67ca89SAndroid Build Coastguard Worker"""
2641*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2642*8d67ca89SAndroid Build Coastguard Workerstatic const char * arr[] = {
2643*8d67ca89SAndroid Build Coastguard Worker  "foo", "bar", "baz",
2644*8d67ca89SAndroid Build Coastguard Worker};
2645*8d67ca89SAndroid Build Coastguard Workerstatic int another_arr[5] = {
2646*8d67ca89SAndroid Build Coastguard Worker  1, 2, 3, 4, 5
2647*8d67ca89SAndroid Build Coastguard Worker};
2648*8d67ca89SAndroid Build Coastguard Worker"""
2649*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2650*8d67ca89SAndroid Build Coastguard Worker
2651*8d67ca89SAndroid Build Coastguard Worker    def test_token_replacement(self):
2652*8d67ca89SAndroid Build Coastguard Worker        text = """\
2653*8d67ca89SAndroid Build Coastguard Worker#define SIGRTMIN 32
2654*8d67ca89SAndroid Build Coastguard Worker#define SIGRTMAX _NSIG
2655*8d67ca89SAndroid Build Coastguard Worker#define SIGRTMAX(a,class) some_func(a, class)
2656*8d67ca89SAndroid Build Coastguard Worker"""
2657*8d67ca89SAndroid Build Coastguard Worker        expected = """\
2658*8d67ca89SAndroid Build Coastguard Worker#define __SIGRTMIN 32
2659*8d67ca89SAndroid Build Coastguard Worker#define __SIGRTMAX _KERNEL__NSIG
2660*8d67ca89SAndroid Build Coastguard Worker#define __SIGRTMAX(a,__linux_class) some_func(a, __linux_class)
2661*8d67ca89SAndroid Build Coastguard Worker"""
2662*8d67ca89SAndroid Build Coastguard Worker        self.assertEqual(self.parse(text), expected)
2663*8d67ca89SAndroid Build Coastguard Worker
2664*8d67ca89SAndroid Build Coastguard Worker
2665*8d67ca89SAndroid Build Coastguard Workerif __name__ == '__main__':
2666*8d67ca89SAndroid Build Coastguard Worker    unittest.main()
2667