1d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#!/usr/bin/python
2d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao"""A glorified C pre-processor parser."""
3d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
4d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport ctypes
5d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport logging
6d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport os
7d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport re
8d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport site
9d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport utils
10d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
11d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baotop = os.getenv('ANDROID_BUILD_TOP')
12d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoif top is None:
13d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    utils.panic('ANDROID_BUILD_TOP not set.\n')
14d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
15d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao# Set up the env vars for libclang.
16d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baosite.addsitedir(os.path.join(top, 'external/clang/bindings/python'))
17d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
18d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoimport clang.cindex
19d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import conf
20d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import Cursor
21d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import CursorKind
22d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import SourceLocation
23d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import SourceRange
24d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import TokenGroup
25d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import TokenKind
26d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom clang.cindex import TranslationUnit
27d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
287592008030a67ebe0dbda20aa041d5c347170611Tao Bao# Set up LD_LIBRARY_PATH to include libclang.so, libLLVM.so, and etc.
297592008030a67ebe0dbda20aa041d5c347170611Tao Bao# Note that setting LD_LIBRARY_PATH with os.putenv() sometimes doesn't help.
307592008030a67ebe0dbda20aa041d5c347170611Tao Baoclang.cindex.Config.set_library_path(os.path.join(top, 'prebuilts/sdk/tools/linux/lib64'))
317592008030a67ebe0dbda20aa041d5c347170611Tao Bao
32d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom defaults import kCppUndefinedMacro
33d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom defaults import kernel_remove_config_macros
34d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baofrom defaults import kernel_token_replacements
35d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
36d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
37d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaodebugBlockParser = False
38d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaodebugCppExpr = False
39d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaodebugOptimIf01 = False
40d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
41d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao###############################################################################
42d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao###############################################################################
43d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                     #####
44d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####           C P P   T O K E N S                                       #####
45d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                     #####
46d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao###############################################################################
47d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao###############################################################################
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# the list of supported C-preprocessor tokens
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project# plus a couple of C tokens as well
51d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokEOF = "\0"
52d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLN = "\n"
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjecttokSTRINGIFY = "#"
54d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokCONCAT = "##"
55d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLOGICAND = "&&"
56d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLOGICOR = "||"
57d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokSHL = "<<"
58d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokSHR = ">>"
59d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokEQUAL = "=="
60d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokNEQUAL = "!="
61d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLT = "<"
62d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLTE = "<="
63d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokGT = ">"
64d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokGTE = ">="
65d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokELLIPSIS = "..."
66d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokSPACE = " "
67d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokDEFINED = "defined"
68d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLPAREN = "("
69d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokRPAREN = ")"
70d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokNOT = "!"
71d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokPLUS = "+"
72d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokMINUS = "-"
73d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokMULTIPLY = "*"
74d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokDIVIDE = "/"
75d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokMODULUS = "%"
76d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokBINAND = "&"
77d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokBINOR = "|"
78d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokBINXOR = "^"
79d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokCOMMA = ","
80d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokLBRACE = "{"
81d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokRBRACE = "}"
82d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokARROW = "->"
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjecttokINCREMENT = "++"
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjecttokDECREMENT = "--"
85d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokNUMBER = "<number>"
86d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokIDENT = "<ident>"
87d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaotokSTRING = "<string>"
88d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
89d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
90d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass Token(clang.cindex.Token):
91d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A class that represents one token after parsing.
92d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
93d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    It inherits the class in libclang, with an extra id property to hold the
94d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    new spelling of the token. The spelling property in the base class is
95d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    defined as read-only. New names after macro instantiation are saved in
96d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    their ids now. It also facilitates the renaming of directive optimizations
97d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    like replacing 'ifndef X' with 'if !defined(X)'.
98d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
99d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    It also overrides the cursor property of the base class. Because the one
100d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    in libclang always queries based on a single token, which usually doesn't
101d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    hold useful information. The cursor in this class can be set by calling
102d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    CppTokenizer.getTokensWithCursors(). Otherwise it returns the one in the
103d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    base class.
104d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """
105d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
106d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, tu=None, group=None, int_data=None, ptr_data=None,
107d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                 cursor=None):
108d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        clang.cindex.Token.__init__(self)
109d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._id = None
110d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tu = tu
111d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._group = group
112d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._cursor = cursor
113d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # self.int_data and self.ptr_data are from the base class. But
114d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # self.int_data doesn't accept a None value.
115d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if int_data is not None:
116d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.int_data = int_data
117d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.ptr_data = ptr_data
118d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
119d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @property
120d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def id(self):
121d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Name of the token."""
122d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._id is None:
123d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return self.spelling
124d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        else:
125d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return self._id
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
127d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @id.setter
128d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def id(self, new_id):
129d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Setting name of the token."""
130d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._id = new_id
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
132d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @property
133d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def cursor(self):
134d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._cursor is None:
135d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._cursor = clang.cindex.Token.cursor
136d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self._cursor
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
138d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @cursor.setter
139d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def cursor(self, new_cursor):
140d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._cursor = new_cursor
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __repr__(self):
143d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self.id == 'defined':
144d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return self.id
145d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        elif self.kind == TokenKind.IDENTIFIER:
146d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return "(ident %s)" % self.id
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.id
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __str__(self):
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.id
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
154d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass BadExpectedToken(Exception):
155d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """An exception that will be raised for unexpected tokens."""
156d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    pass
157d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
158d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
159d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao# The __contains__ function in libclang SourceRange class contains a bug. It
160d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao# gives wrong result when dealing with single line range.
161d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao# Bug filed with upstream:
162d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao# http://llvm.org/bugs/show_bug.cgi?id=22243, http://reviews.llvm.org/D7277
163d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef SourceRange__contains__(self, other):
164d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Determine if a given location is inside the range."""
165d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    if not isinstance(other, SourceLocation):
166d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return False
167d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    if other.file is None and self.start.file is None:
168d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        pass
169d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    elif (self.start.file.name != other.file.name or
170d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao          other.file.name != self.end.file.name):
171d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # same file name
172d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return False
173d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # same file, in between lines
174d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    if self.start.line < other.line < self.end.line:
175d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return True
176d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # same file, same line
177d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    elif self.start.line == other.line == self.end.line:
178d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self.start.column <= other.column <= self.end.column:
179d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return True
180d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    elif self.start.line == other.line:
181d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # same file first line
182d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self.start.column <= other.column:
183d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return True
184d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    elif other.line == self.end.line:
185d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # same file last line
186d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if other.column <= self.end.column:
187d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return True
188d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    return False
189d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
190d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
191d7db594b8d1dab36b711bd887a9dd21675c87243Tao BaoSourceRange.__contains__ = SourceRange__contains__
192d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
193d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
194d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
195d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
196d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
197d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####           C P P   T O K E N I Z E R                                  #####
198d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
199d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
200d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
201d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
202d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
203d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass CppTokenizer(object):
204d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A tokenizer that converts some input text into a list of tokens.
205d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
206d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    It calls libclang's tokenizer to get the parsed tokens. In addition, it
207d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    updates the cursor property in each token after parsing, by calling
208d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    getTokensWithCursors().
209d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """
210d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
211d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    clang_flags = ['-E', '-x', 'c']
212d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    options = TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
214d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self):
215d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Initialize a new CppTokenizer object."""
216d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._indexer = clang.cindex.Index.create()
217d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tu = None
218d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index = 0
219d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.tokens = None
220d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
221d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def _getTokensWithCursors(self):
222d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Helper method to return all tokens with their cursors.
223d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
224d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        The cursor property in a clang Token doesn't provide enough
225d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        information. Because it is queried based on single token each time
226d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        without any context, i.e. via calling conf.lib.clang_annotateTokens()
227d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        with only one token given. So we often see 'INVALID_FILE' in one
228d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        token's cursor. In this function it passes all the available tokens
229d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        to get more informative cursors.
230d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """
231d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
232d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        tokens_memory = ctypes.POINTER(clang.cindex.Token)()
233d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        tokens_count = ctypes.c_uint()
234d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
235d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        conf.lib.clang_tokenize(self._tu, self._tu.cursor.extent,
236d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                ctypes.byref(tokens_memory),
237d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                ctypes.byref(tokens_count))
238d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
239d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        count = int(tokens_count.value)
240d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
241d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # If we get no tokens, no memory was allocated. Be sure not to return
242d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # anything and potentially call a destructor on nothing.
243d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if count < 1:
244d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
246d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        cursors = (Cursor * count)()
247d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        cursors_memory = ctypes.cast(cursors, ctypes.POINTER(Cursor))
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
249d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        conf.lib.clang_annotateTokens(self._tu, tokens_memory, count,
250d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                      cursors_memory)
2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
252d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        tokens_array = ctypes.cast(
253d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokens_memory,
254d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            ctypes.POINTER(clang.cindex.Token * count)).contents
255d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        token_group = TokenGroup(self._tu, tokens_memory, tokens_count)
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
257d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        tokens = []
258d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        for i in xrange(0, count):
259d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            token = Token(self._tu, token_group,
260d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          int_data=tokens_array[i].int_data,
261d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          ptr_data=tokens_array[i].ptr_data,
262d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          cursor=cursors[i])
263d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # We only want non-comment tokens.
264d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if token.kind != TokenKind.COMMENT:
265d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                tokens.append(token)
266d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
267d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return tokens
268d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
269d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def parseString(self, lines):
270d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Parse a list of text lines into a BlockList object."""
271d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        file_ = 'dummy.c'
272d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tu = self._indexer.parse(file_, self.clang_flags,
273d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                       unsaved_files=[(file_, lines)],
274d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                       options=self.options)
275d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.tokens = self._getTokensWithCursors()
276d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
277d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def parseFile(self, file_):
278d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Parse a file into a BlockList object."""
279d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tu = self._indexer.parse(file_, self.clang_flags,
280d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                       options=self.options)
281d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.tokens = self._getTokensWithCursors()
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
283d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def nextToken(self):
284d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return next token from the list."""
285d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index < len(self.tokens):
286d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            t = self.tokens[self._index]
287d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
288d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return t
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
290d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return None
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
293d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass CppStringTokenizer(CppTokenizer):
294d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A CppTokenizer derived class that accepts a string of text as input."""
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
296d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, line):
297d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        CppTokenizer.__init__(self)
298d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.parseString(line)
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
301d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass CppFileTokenizer(CppTokenizer):
302d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A CppTokenizer derived class that accepts a file as input."""
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
304d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, file_):
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        CppTokenizer.__init__(self)
306d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.parseFile(file_)
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
309d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao# Unit testing
310d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#
311d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass CppTokenizerTester(object):
312d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A class used to test CppTokenizer classes."""
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
314d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, tokenizer=None):
315d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tokenizer = tokenizer
316d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._token = None
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
318d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def setTokenizer(self, tokenizer):
319d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tokenizer = tokenizer
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
321d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def expect(self, id):
322d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._token = self._tokenizer.nextToken()
323d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._token is None:
324d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokid = ''
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
326d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokid = self._token.id
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if tokid == id:
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return
329d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        raise BadExpectedToken("###  BAD TOKEN: '%s' expecting '%s'" % (
330d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokid, id))
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
332d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def expectToken(self, id, line, col):
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.expect(id)
334d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._token.location.line != line:
335d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            raise BadExpectedToken(
336d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                "###  BAD LINENO: token '%s' got '%d' expecting '%d'" % (
337d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    id, self._token.lineno, line))
338d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._token.location.column != col:
339d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            raise BadExpectedToken("###  BAD COLNO: '%d' expecting '%d'" % (
340d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                self._token.colno, col))
341d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
342d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def expectTokens(self, tokens):
343d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        for id, line, col in tokens:
344d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.expectToken(id, line, col)
345d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
346d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def expectList(self, list_):
347d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        for item in list_:
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self.expect(item)
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
350d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef test_CppTokenizer():
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    tester = CppTokenizerTester()
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
354d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("#an/example  && (01923_xy)"))
355d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectList(["#", "an", "/", "example", tokLOGICAND, tokLPAREN,
356d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "01923_xy", tokRPAREN])
357d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
358d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("FOO(BAR) && defined(BAZ)"))
359d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectList(["FOO", tokLPAREN, "BAR", tokRPAREN, tokLOGICAND,
360d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "defined", tokLPAREN, "BAZ", tokRPAREN])
361d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
362d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("/*\n#\n*/"))
363d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectList([])
364d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
365d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("first\nsecond"))
366d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectList(["first", "second"])
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
368d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("first second\n  third"))
369d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectTokens([("first", 1, 1),
370d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                         ("second", 1, 7),
371d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                         ("third", 2, 3)])
372d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
373d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("boo /* what the\nhell */"))
374d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectTokens([("boo", 1, 1)])
375d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
376d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.setTokenizer(CppStringTokenizer("an \\\n example"))
377d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    tester.expectTokens([("an", 1, 1),
378d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                         ("example", 2, 2)])
3791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return True
3801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
382d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
383d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
384d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
385d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####           C P P   E X P R E S S I O N S                              #####
386d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
387d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
388d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
389d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
391d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass CppExpr(object):
392d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A class that models the condition of #if directives into an expr tree.
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
394d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    Each node in the tree is of the form (op, arg) or (op, arg1, arg2) where
395d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    "op" is a string describing the operation
396d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """
397d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
398d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    unaries = ["!", "~"]
399d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    binaries = ["+", "-", "<", "<=", ">=", ">", "&&", "||", "*", "/", "%",
400d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                "&", "|", "^", "<<", ">>", "==", "!=", "?", ":"]
4011198fd38645ff94bf48daae10f8b74903444badcElliott Hughes    precedences = {
4021198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "?": 1, ":": 1,
4031198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "||": 2,
4041198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "&&": 3,
4051198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "|": 4,
4061198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "^": 5,
4071198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "&": 6,
4081198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "==": 7, "!=": 7,
4091198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "<": 8, "<=": 8, ">": 8, ">=": 8,
4101198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "<<": 9, ">>": 9,
4111198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "+": 10, "-": 10,
4121198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "*": 11, "/": 11, "%": 11,
4131198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        "!": 12, "~": 12
4141198fd38645ff94bf48daae10f8b74903444badcElliott Hughes    }
4151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __init__(self, tokens):
417d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Initialize a CppExpr. 'tokens' must be a CppToken list."""
418d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.tokens = tokens
419d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._num_tokens = len(tokens)
420d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index = 0
421d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
4221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if debugCppExpr:
4231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            print "CppExpr: trying to parse %s" % repr(tokens)
42440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        self.expr = self.parseExpression(0)
4251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if debugCppExpr:
42640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            print "CppExpr: got " + repr(self.expr)
427d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index != self._num_tokens:
428d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.throw(BadExpectedToken, "crap at end of input (%d != %d): %s"
429d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       % (self._index, self._num_tokens, repr(tokens)))
4301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
43140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def throw(self, exception, msg):
432d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index < self._num_tokens:
433d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tok = self.tokens[self._index]
434d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            print "%d:%d: %s" % (tok.location.line, tok.location.column, msg)
4351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
4361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            print "EOF: %s" % msg
43740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        raise exception(msg)
4381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
43940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def expectId(self, id):
440d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Check that a given token id is at the current position."""
441d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        token = self.tokens[self._index]
442d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens or token.id != id:
443d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.throw(BadExpectedToken,
444d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "### expecting '%s' in expression, got '%s'" % (
445d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                           id, token.id))
446d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
44740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
44840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def is_decimal(self):
449d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        token = self.tokens[self._index].id
450d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if token[-1] in "ULul":
451d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            token = token[:-1]
452d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        try:
453d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            val = int(token, 10)
454d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
455d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return ('int', val)
456d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        except ValueError:
457d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return None
4581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
459d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def is_octal(self):
460d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        token = self.tokens[self._index].id
461d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if token[-1] in "ULul":
462d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            token = token[:-1]
463d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if len(token) < 2 or token[0] != '0':
464d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return None
465d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        try:
466d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            val = int(token, 8)
467d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
468d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return ('oct', val)
469d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        except ValueError:
470d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return None
47140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
47240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def is_hexadecimal(self):
473d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        token = self.tokens[self._index].id
474d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if token[-1] in "ULul":
475d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            token = token[:-1]
476d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if len(token) < 3 or (token[:2] != '0x' and token[:2] != '0X'):
477d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return None
478d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        try:
479d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            val = int(token, 16)
480d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
481d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return ('hex', val)
482d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        except ValueError:
483d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return None
48440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
48540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def is_integer(self):
486d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self.tokens[self._index].kind != TokenKind.LITERAL:
4871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
4881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
48940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        c = self.is_hexadecimal()
490d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if c:
491d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return c
4921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
493d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        c = self.is_octal()
494d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if c:
495d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return c
4961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
497d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        c = self.is_decimal()
498d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if c:
499d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return c
500d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
501d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return None
50240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
50340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def is_number(self):
504d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        t = self.tokens[self._index]
505d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if t.id == tokMINUS and self._index + 1 < self._num_tokens:
506d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
50740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            c = self.is_integer()
5081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if c:
509d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                op, val = c
51040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                return (op, -val)
511d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if t.id == tokPLUS and self._index + 1 < self._num_tokens:
512d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
51340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            c = self.is_integer()
514d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if c:
515d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                return c
5161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
51740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        return self.is_integer()
5181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
51940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def is_defined(self):
520d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        t = self.tokens[self._index]
5211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if t.id != tokDEFINED:
5221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
5231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
524d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # We have the defined keyword, check the rest.
525d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
526d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        used_parens = False
527d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if (self._index < self._num_tokens and
528d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.tokens[self._index].id == tokLPAREN):
529d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            used_parens = True
530d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
531d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
532d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens:
533d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.throw(BadExpectedToken,
534d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "### 'defined' must be followed by macro name or left "
535d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "paren")
536d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
537d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        t = self.tokens[self._index]
538d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if t.kind != TokenKind.IDENTIFIER:
539d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.throw(BadExpectedToken,
540d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "### 'defined' must be followed by macro name")
541d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
542d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
543fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes        if used_parens:
54440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            self.expectId(tokRPAREN)
5451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
546d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return ("defined", t.id)
5471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
54840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def is_call_or_ident(self):
549d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens:
5501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
5511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
552d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        t = self.tokens[self._index]
553d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if t.kind != TokenKind.IDENTIFIER:
5541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
5551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
556d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        name = t.id
5571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
558d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
559d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if (self._index >= self._num_tokens or
560d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.tokens[self._index].id != tokLPAREN):
56140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return ("ident", name)
5621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
563d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        params = []
564d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        depth = 1
565d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
566d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        j = self._index
567d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        while self._index < self._num_tokens:
568d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            id = self.tokens[self._index].id
5691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if id == tokLPAREN:
5701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                depth += 1
5711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            elif depth == 1 and (id == tokCOMMA or id == tokRPAREN):
572d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                k = self._index
573d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                param = self.tokens[j:k]
57440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                params.append(param)
5751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if id == tokRPAREN:
5761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    break
577d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                j = self._index + 1
5781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            elif id == tokRPAREN:
5791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                depth -= 1
580d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self._index += 1
5811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
582d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens:
5831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
5841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
585d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
58640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        return ("call", (name, params))
5871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
588d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # Implements the "precedence climbing" algorithm from
589d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm.
590d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # The "classic" algorithm would be fine if we were using a tool to
591d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # generate the parser, but we're not. Dijkstra's "shunting yard"
592d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # algorithm hasn't been necessary yet.
5931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
59440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def parseExpression(self, minPrecedence):
595d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens:
59640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return None
5971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
59840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        node = self.parsePrimary()
599d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        while (self.token() and self.isBinary(self.token()) and
600d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao               self.precedence(self.token()) >= minPrecedence):
60140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            op = self.token()
60240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            self.nextToken()
60340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            rhs = self.parseExpression(self.precedence(op) + 1)
60440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            node = (op.id, node, rhs)
60540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
60640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        return node
60740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
60840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def parsePrimary(self):
60940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        op = self.token()
61040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        if self.isUnary(op):
61140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            self.nextToken()
61240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return (op.id, self.parseExpression(self.precedence(op)))
61340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
61440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        primary = None
61540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        if op.id == tokLPAREN:
61640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            self.nextToken()
61740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            primary = self.parseExpression(0)
61840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            self.expectId(tokRPAREN)
6191198fd38645ff94bf48daae10f8b74903444badcElliott Hughes        elif op.id == "?":
6201198fd38645ff94bf48daae10f8b74903444badcElliott Hughes            self.nextToken()
6211198fd38645ff94bf48daae10f8b74903444badcElliott Hughes            primary = self.parseExpression(0)
6221198fd38645ff94bf48daae10f8b74903444badcElliott Hughes            self.expectId(":")
623d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        elif op.id == '+' or op.id == '-' or op.kind == TokenKind.LITERAL:
62440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            primary = self.is_number()
625d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # Checking for 'defined' needs to come first now because 'defined' is
626d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # recognized as IDENTIFIER.
62740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        elif op.id == tokDEFINED:
62840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            primary = self.is_defined()
629d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        elif op.kind == TokenKind.IDENTIFIER:
630d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            primary = self.is_call_or_ident()
63140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        else:
632d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.throw(BadExpectedToken,
633d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "didn't expect to see a %s in factor" % (
634d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                           self.tokens[self._index].id))
635d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return primary
6361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
63740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def isBinary(self, token):
63840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        return token.id in self.binaries
6391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
64040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def isUnary(self, token):
64140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        return token.id in self.unaries
6421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
64340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def precedence(self, token):
64440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        return self.precedences.get(token.id)
6451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
64640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def token(self):
647d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens:
6481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
649d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.tokens[self._index]
6501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
65140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def nextToken(self):
652d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._index += 1
653d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self._index >= self._num_tokens:
65440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return None
655d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.tokens[self._index]
6561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
65740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def dump_node(self, e):
6581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        op = e[0]
6591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        line = "(" + op
6601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op == "int":
6611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " %d)" % e[1]
662d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        elif op == "oct":
663d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            line += " 0%o)" % e[1]
6641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "hex":
6651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " 0x%x)" % e[1]
6661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "ident":
6671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " %s)" % e[1]
6681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "defined":
6691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " %s)" % e[1]
6701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "call":
6711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            arg = e[1]
6721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " %s [" % arg[0]
6731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            prefix = ""
6741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for param in arg[1]:
6751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                par = ""
6761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for tok in param:
6771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    par += str(tok)
6781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                line += "%s%s" % (prefix, par)
6791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                prefix = ","
6801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += "])"
6811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op in CppExpr.unaries:
6821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " %s)" % self.dump_node(e[1])
6831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op in CppExpr.binaries:
6841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " %s %s)" % (self.dump_node(e[1]), self.dump_node(e[2]))
6851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
6861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            line += " ?%s)" % repr(e[1])
6871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return line
6891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
6901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __repr__(self):
6911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.dump_node(self.expr)
6921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
69340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    def source_node(self, e):
6941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        op = e[0]
6951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op == "int":
6961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return "%d" % e[1]
6971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op == "hex":
6981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return "0x%x" % e[1]
699d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if op == "oct":
700d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return "0%o" % e[1]
7011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op == "ident":
7021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            # XXX: should try to expand
7031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return e[1]
7041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op == "defined":
7051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return "defined(%s)" % e[1]
7061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
707d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        prec = CppExpr.precedences.get(op, 1000)
708d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        arg = e[1]
7091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op in CppExpr.unaries:
7101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            arg_src = self.source_node(arg)
711d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            arg_op = arg[0]
712d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            arg_prec = CppExpr.precedences.get(arg_op, 1000)
7131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if arg_prec < prec:
7141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return "!(" + arg_src + ")"
7151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            else:
7161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return "!" + arg_src
7171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op in CppExpr.binaries:
718d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            arg2 = e[2]
719d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            arg1_op = arg[0]
720d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            arg2_op = arg2[0]
7211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            arg1_src = self.source_node(arg)
7221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            arg2_src = self.source_node(arg2)
723d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if CppExpr.precedences.get(arg1_op, 1000) < prec:
7241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                arg1_src = "(%s)" % arg1_src
725d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if CppExpr.precedences.get(arg2_op, 1000) < prec:
7261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                arg2_src = "(%s)" % arg2_src
7271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return "%s %s %s" % (arg1_src, op, arg2_src)
7291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return "???"
7301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __str__(self):
7321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.source_node(self.expr)
7331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
734d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @staticmethod
735d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def int_node(e):
736d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if e[0] in ["int", "oct", "hex"]:
7371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return e[1]
7381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
7391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
7401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def toInt(self):
7421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.int_node(self.expr)
7431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
744d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def optimize_node(self, e, macros=None):
745d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if macros is None:
746d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            macros = {}
7471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        op = e[0]
748d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
7491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if op == "defined":
75040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            op, name = e
7511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if macros.has_key(name):
7521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if macros[name] == kCppUndefinedMacro:
7531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return ("int", 0)
7541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else:
755d3e64a3f403918abf2cc3f9f0f9a2204a420ec96Elliott Hughes                    try:
756d3e64a3f403918abf2cc3f9f0f9a2204a420ec96Elliott Hughes                        value = int(macros[name])
757d3e64a3f403918abf2cc3f9f0f9a2204a420ec96Elliott Hughes                        return ("int", value)
758d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    except ValueError:
759d3e64a3f403918abf2cc3f9f0f9a2204a420ec96Elliott Hughes                        return ("defined", macros[name])
7601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if kernel_remove_config_macros and name.startswith("CONFIG_"):
7621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return ("int", 0)
7631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
76440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return e
76540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
76640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        elif op == "ident":
76740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            op, name = e
76840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            if macros.has_key(name):
76940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                try:
77040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                    value = int(macros[name])
77140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                    expanded = ("int", value)
772d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                except ValueError:
77340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                    expanded = ("ident", macros[name])
77440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                return self.optimize_node(expanded, macros)
77540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return e
77640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
7771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "!":
7781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            op, v = e
7791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            v = self.optimize_node(v, macros)
7801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if v[0] == "int":
7811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if v[1] == 0:
7821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return ("int", 1)
7831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else:
7841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return ("int", 0)
78540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return ('!', v)
7861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
7871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "&&":
7881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            op, l, r = e
789d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            l = self.optimize_node(l, macros)
790d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            r = self.optimize_node(r, macros)
7911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            li = self.int_node(l)
7921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ri = self.int_node(r)
793d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if li is not None:
7941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if li == 0:
7951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return ("int", 0)
7961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else:
7971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return r
798d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif ri is not None:
79940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                if ri == 0:
80040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                    return ("int", 0)
80140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                else:
80240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes                    return l
80340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return (op, l, r)
8041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif op == "||":
8061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            op, l, r = e
807d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            l = self.optimize_node(l, macros)
808d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            r = self.optimize_node(r, macros)
8091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            li = self.int_node(l)
8101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            ri = self.int_node(r)
811d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if li is not None:
8121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if li == 0:
8131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return r
8141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else:
8151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return ("int", 1)
816d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif ri is not None:
8171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if ri == 0:
8181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return l
8191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else:
8201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return ("int", 1)
82140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return (op, l, r)
8221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
82340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        else:
82440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes            return e
8251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
826d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def optimize(self, macros=None):
827d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if macros is None:
828d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            macros = {}
82940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        self.expr = self.optimize_node(self.expr, macros)
8301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
8321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef test_cpp_expr(expr, expected):
833d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    e = CppExpr(CppStringTokenizer(expr).tokens)
8341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    s1 = repr(e)
8351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if s1 != expected:
836d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        print ("[FAIL]: expression '%s' generates '%s', should be "
837d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao               "'%s'" % (expr, s1, expected))
83840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        global failure_count
83940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        failure_count += 1
8401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
841d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
842d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef test_cpp_expr_optim(expr, expected, macros=None):
843d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    if macros is None:
844d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        macros = {}
845d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    e = CppExpr(CppStringTokenizer(expr).tokens)
8461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    e.optimize(macros)
8471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    s1 = repr(e)
8481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if s1 != expected:
849d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        print ("[FAIL]: optimized expression '%s' generates '%s' with "
850d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao               "macros %s, should be '%s'" % (expr, s1, macros, expected))
85140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        global failure_count
85240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        failure_count += 1
8531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
854d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
8551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef test_cpp_expr_source(expr, expected):
856d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    e = CppExpr(CppStringTokenizer(expr).tokens)
8571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    s1 = str(e)
8581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if s1 != expected:
859d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        print ("[FAIL]: source expression '%s' generates '%s', should "
860d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao               "be '%s'" % (expr, s1, expected))
86140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        global failure_count
86240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        failure_count += 1
8631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
864d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
8651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef test_CppExpr():
86640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("0", "(int 0)")
86740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("1", "(int 1)")
868d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("-5", "(int -5)")
869d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("+1", "(int 1)")
870d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("0U", "(int 0)")
871d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("015", "(oct 015)")
872d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("015l", "(oct 015)")
873d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("0x3e", "(hex 0x3e)")
87440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("(0)", "(int 0)")
87540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("1 && 1", "(&& (int 1) (int 1))")
87640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("1 && 0", "(&& (int 1) (int 0))")
87740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("EXAMPLE", "(ident EXAMPLE)")
87840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("EXAMPLE - 3", "(- (ident EXAMPLE) (int 3))")
87940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("defined(EXAMPLE)", "(defined EXAMPLE)")
88040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("defined ( EXAMPLE ) ", "(defined EXAMPLE)")
88140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr("!defined(EXAMPLE)", "(! (defined EXAMPLE))")
882d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("defined(ABC) || defined(BINGO)",
883d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                  "(|| (defined ABC) (defined BINGO))")
884d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("FOO(BAR,5)", "(call FOO [BAR,5])")
885d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr("A == 1 || defined(B)",
886d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                  "(|| (== (ident A) (int 1)) (defined B))")
88740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
88840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("0", "(int 0)")
88940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("1", "(int 1)")
89040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("1 && 1", "(int 1)")
891d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("1 && +1", "(int 1)")
892d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("0x1 && 01", "(oct 01)")
89340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("1 && 0", "(int 0)")
89440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("0 && 1", "(int 0)")
89540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("0 && 0", "(int 0)")
89640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("1 || 1", "(int 1)")
89740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("1 || 0", "(int 1)")
89840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("0 || 1", "(int 1)")
89940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("0 || 0", "(int 0)")
90040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("A", "(ident A)")
901d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("A", "(int 1)", {"A": 1})
902d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("A || B", "(int 1)", {"A": 1})
903d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("A || B", "(int 1)", {"B": 1})
904d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("A && B", "(ident B)", {"A": 1})
905d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("A && B", "(ident A)", {"B": 1})
90640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("A && B", "(&& (ident A) (ident B))")
90740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("EXAMPLE", "(ident EXAMPLE)")
90840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("EXAMPLE - 3", "(- (ident EXAMPLE) (int 3))")
90940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("defined(EXAMPLE)", "(defined EXAMPLE)")
910d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(EXAMPLE)", "(defined XOWOE)",
911d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"EXAMPLE": "XOWOE"})
912d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(EXAMPLE)", "(int 0)",
913d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"EXAMPLE": kCppUndefinedMacro})
91440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_optim("!defined(EXAMPLE)", "(! (defined EXAMPLE))")
915d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("!defined(EXAMPLE)", "(! (defined XOWOE))",
916d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"EXAMPLE": "XOWOE"})
917d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("!defined(EXAMPLE)", "(int 1)",
918d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"EXAMPLE": kCppUndefinedMacro})
919d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) || defined(B)",
920d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "(|| (defined A) (defined B))")
921d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) || defined(B)", "(int 1)", {"A": "1"})
922d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) || defined(B)", "(int 1)", {"B": "1"})
923d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) || defined(B)", "(defined A)",
924d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"B": kCppUndefinedMacro})
925d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) || defined(B)", "(int 0)",
926d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"A": kCppUndefinedMacro, "B": kCppUndefinedMacro})
927d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) && defined(B)",
928d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "(&& (defined A) (defined B))")
929d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) && defined(B)",
930d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "(defined B)", {"A": "1"})
931d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) && defined(B)",
932d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "(defined A)", {"B": "1"})
933d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) && defined(B)", "(int 0)",
934d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        {"B": kCppUndefinedMacro})
935d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("defined(A) && defined(B)",
936d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "(int 0)", {"A": kCppUndefinedMacro})
937d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim("A == 1 || defined(B)",
938d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "(|| (== (ident A) (int 1)) (defined B))")
939d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_cpp_expr_optim(
940d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        "defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)",
941d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        "(|| (! (defined __GLIBC__)) (< (ident __GLIBC__) (int 2)))",
942d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        {"__KERNEL__": kCppUndefinedMacro})
94340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
94440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("0", "0")
94540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("1", "1")
94640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("1 && 1", "1 && 1")
94740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("1 && 0", "1 && 0")
94840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("0 && 1", "0 && 1")
94940596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("0 && 0", "0 && 0")
95040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("1 || 1", "1 || 1")
95140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("1 || 0", "1 || 0")
95240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("0 || 1", "0 || 1")
95340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("0 || 0", "0 || 0")
95440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("EXAMPLE", "EXAMPLE")
95540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("EXAMPLE - 3", "EXAMPLE - 3")
95640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("defined(EXAMPLE)", "defined(EXAMPLE)")
95740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("defined EXAMPLE", "defined(EXAMPLE)")
95840596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes    test_cpp_expr_source("A == 1 || defined(B)", "A == 1 || defined(B)")
9591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
961d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
962d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
963d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
964d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####          C P P   B L O C K                                           #####
965d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
966d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
967d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
9681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
970d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass Block(object):
971d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A class used to model a block of input source text.
972d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
973d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    There are two block types:
974d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao      - directive blocks: contain the tokens of a single pre-processor
975d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        directive (e.g. #if)
976d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao      - text blocks, contain the tokens of non-directive blocks
977d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
978d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    The cpp parser class below will transform an input source file into a list
979d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    of Block objects (grouped in a BlockList object for convenience)
980d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """
981d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
982d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, tokens, directive=None, lineno=0, identifier=None):
983d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Initialize a new block, if 'directive' is None, it is a text block.
984d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
985d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        NOTE: This automatically converts '#ifdef MACRO' into
986d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        '#if defined(MACRO)' and '#ifndef MACRO' into '#if !defined(MACRO)'.
987d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """
9881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if directive == "ifdef":
9901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tok = Token()
991d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tok.id = tokDEFINED
992d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokens = [tok] + tokens
9931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            directive = "if"
9941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
9951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        elif directive == "ifndef":
9961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tok1 = Token()
9971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            tok2 = Token()
998d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tok1.id = tokNOT
999d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tok2.id = tokDEFINED
1000d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokens = [tok1, tok2] + tokens
10011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            directive = "if"
10021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1003d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.tokens = tokens
10041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.directive = directive
1005d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.define_id = identifier
10061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if lineno > 0:
10071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            self.lineno = lineno
10081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
1009d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.lineno = self.tokens[0].location.line
10101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if self.isIf():
1012d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            self.expr = CppExpr(self.tokens)
10131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def isDirective(self):
1015d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return True iff this is a directive block."""
1016d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.directive is not None
10171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def isConditional(self):
1019d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return True iff this is a conditional directive block."""
1020d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.directive in ["if", "ifdef", "ifndef", "else", "elif",
1021d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                  "endif"]
10221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def isDefine(self):
1024d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return the macro name in a #define directive, or None otherwise."""
10251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if self.directive != "define":
10261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
1027d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.define_id
10281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
10291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def isIf(self):
1030d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return True iff this is an #if-like directive block."""
1031d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.directive in ["if", "ifdef", "ifndef", "elif"]
10321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1033d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def isEndif(self):
1034d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return True iff this is an #endif directive block."""
1035d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.directive == "endif"
10361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1037d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def isInclude(self):
1038d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Check whether this is a #include directive.
10391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1040d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        If true, returns the corresponding file name (with brackets or
1041d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        double-qoutes). None otherwise.
1042d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """
10431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1044d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self.directive != "include":
10451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return None
1046d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return ''.join([str(x) for x in self.tokens])
10471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1048d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @staticmethod
1049d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def format_blocks(tokens, indent=0):
1050d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return the formatted lines of strings with proper indentation."""
1051d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        newline = True
1052d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        result = []
1053d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        buf = ''
1054d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        i = 0
1055d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        while i < len(tokens):
1056d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            t = tokens[i]
1057d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if t.id == '{':
1058d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf += ' {'
1059d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result.append(strip_space(buf))
1060d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                indent += 2
1061d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf = ''
1062d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                newline = True
1063d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif t.id == '}':
1064d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                indent -= 2
1065d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if not newline:
1066d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    result.append(strip_space(buf))
1067d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                # Look ahead to determine if it's the end of line.
1068d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if (i + 1 < len(tokens) and
1069d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    (tokens[i+1].id == ';' or
1070d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                     tokens[i+1].id in ['else', '__attribute__',
1071d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                        '__attribute', '__packed'] or
1072d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                     tokens[i+1].kind == TokenKind.IDENTIFIER)):
1073d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf = ' ' * indent + '}'
1074d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    newline = False
1075d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                else:
1076d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    result.append(' ' * indent + '}')
1077d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf = ''
1078d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    newline = True
1079d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif t.id == ';':
1080d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result.append(strip_space(buf) + ';')
1081d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf = ''
1082d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                newline = True
1083d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # We prefer a new line for each constant in enum.
1084d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif t.id == ',' and t.cursor.kind == CursorKind.ENUM_DECL:
1085d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result.append(strip_space(buf) + ',')
1086d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf = ''
1087d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                newline = True
1088d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            else:
1089d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if newline:
1090d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf += ' ' * indent + str(t)
1091d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                else:
1092d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf += ' ' + str(t)
1093d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                newline = False
1094d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            i += 1
1095fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1096d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if buf:
1097d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            result.append(strip_space(buf))
1098fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1099d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return result, indent
1100fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1101d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def writeWithWarning(self, out, warning, left_count, repeat_count, indent):
1102d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Dump the current block with warnings."""
1103fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # removeWhiteSpace() will sometimes creates non-directive blocks
1104fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # without any tokens. These come from blocks that only contained
1105fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # empty lines and spaces. They should not be printed in the final
1106fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # output, and then should not be counted for this operation.
1107fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        #
1108d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if self.directive is None and not self.tokens:
1109d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return left_count, indent
1110fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1111fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        if self.directive:
1112d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            out.write(str(self) + '\n')
1113fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            left_count -= 1
1114fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner            if left_count == 0:
1115fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                out.write(warning)
1116fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                left_count = repeat_count
1117fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1118fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        else:
1119d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            lines, indent = self.format_blocks(self.tokens, indent)
1120d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            for line in lines:
1121d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                out.write(line + '\n')
1122d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                left_count -= 1
1123d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if left_count == 0:
1124d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    out.write(warning)
1125d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    left_count = repeat_count
1126fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1127d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return left_count, indent
1128fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
11291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __repr__(self):
1130d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Generate the representation of a given block."""
11311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if self.directive:
11321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result = "#%s " % self.directive
11331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if self.isIf():
11341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                result += repr(self.expr)
11351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            else:
11361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                for tok in self.tokens:
11371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    result += repr(tok)
11381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
11391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result = ""
11401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            for tok in self.tokens:
11411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                result += repr(tok)
11421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return result
11441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __str__(self):
1146d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Generate the string representation of a given block."""
11471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if self.directive:
1148d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # "#if"
11491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if self.directive == "if":
11501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                # small optimization to re-generate #ifdef and #ifndef
11511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                e = self.expr.expr
11521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                op = e[0]
11531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if op == "defined":
11541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    result = "#ifdef %s" % e[1]
11551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                elif op == "!" and e[1][0] == "defined":
11561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    result = "#ifndef %s" % e[1][1]
11571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                else:
11581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    result = "#if " + str(self.expr)
1159d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1160d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # "#define"
1161d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif self.isDefine():
1162d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result = "#%s %s" % (self.directive, self.define_id)
1163d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if self.tokens:
1164d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    result += " "
1165d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                expr = strip_space(' '.join([tok.id for tok in self.tokens]))
1166d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                # remove the space between name and '(' in function call
1167d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result += re.sub(r'(\w+) \(', r'\1(', expr)
1168d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1169d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # "#error"
1170d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # Concatenating tokens with a space separator, because they may
1171d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            # not be quoted and broken into several tokens
1172d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif self.directive == "error":
1173d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result = "#error %s" % ' '.join([tok.id for tok in self.tokens])
1174d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
11751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            else:
11761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                result = "#%s" % self.directive
1177d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if self.tokens:
11781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    result += " "
1179d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result += ''.join([tok.id for tok in self.tokens])
11801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        else:
1181d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            lines, _ = self.format_blocks(self.tokens)
1182d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            result = '\n'.join(lines)
11831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return result
11851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1186d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1187d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass BlockList(object):
1188d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A convenience class used to hold and process a list of blocks.
1189d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1190d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    It calls the cpp parser to get the blocks.
1191d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """
1192d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1193d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, blocks):
11941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.blocks = blocks
11951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
11961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __len__(self):
11971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return len(self.blocks)
11981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1199d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __getitem__(self, n):
12001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return self.blocks[n]
12011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __repr__(self):
12031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return repr(self.blocks)
12041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def __str__(self):
1206d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        result = '\n'.join([str(b) for b in self.blocks])
12071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return result
12081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1209d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def dump(self):
1210d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Dump all the blocks in current BlockList."""
1211d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        print '##### BEGIN #####'
1212d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        for i, b in enumerate(self.blocks):
1213d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            print '### BLOCK %d ###' % i
1214d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            print b
1215d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        print '##### END #####'
1216d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1217d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def optimizeIf01(self):
1218d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Remove the code between #if 0 .. #endif in a BlockList."""
12191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.blocks = optimize_if01(self.blocks)
12201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def optimizeMacros(self, macros):
1222d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Remove known defined and undefined macros from a BlockList."""
12231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for b in self.blocks:
12241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if b.isIf():
12251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                b.expr.optimize(macros)
12261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1227d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def removeMacroDefines(self, macros):
1228d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Remove known macro definitions from a BlockList."""
1229d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self.blocks = remove_macro_defines(self.blocks, macros)
1230fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1231d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def optimizeAll(self, macros):
12321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.optimizeMacros(macros)
12331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.optimizeIf01()
12341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return
12351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
12361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    def findIncludes(self):
1237d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return the list of included files in a BlockList."""
12381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        result = []
12391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for b in self.blocks:
12401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            i = b.isInclude()
12411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if i:
12421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                result.append(i)
12431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return result
12441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1245d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def write(self, out):
12461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        out.write(str(self))
12471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1248d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def writeWithWarning(self, out, warning, repeat_count):
1249fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        left_count = repeat_count
1250d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        indent = 0
1251fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        for b in self.blocks:
1252d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            left_count, indent = b.writeWithWarning(out, warning, left_count,
1253d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                                    repeat_count, indent)
1254d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1255d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def removeVarsAndFuncs(self, knownStatics=None):
1256d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Remove variable and function declarations.
1257d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1258d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        All extern and static declarations corresponding to variable and
1259d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        function declarations are removed. We only accept typedefs and
1260d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        enum/structs/union declarations.
1261d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1262d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        However, we keep the definitions corresponding to the set of known
1263d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        static inline functions in the set 'knownStatics', which is useful
1264d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        for optimized byteorder swap functions and stuff like that.
1265d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """
1266d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1267d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # NOTE: It's also removing function-like macros, such as __SYSCALL(...)
1268d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # in uapi/asm-generic/unistd.h, or KEY_FIELD(...) in linux/bcache.h.
1269d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # It could be problematic when we have function-like macros but without
1270d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # '}' following them. It will skip all the tokens/blocks until seeing a
1271d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # '}' as the function end. Fortunately we don't have such cases in the
1272d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # current kernel headers.
1273fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
12741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        # state = 0 => normal (i.e. LN + spaces)
1275fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # state = 1 => typedef/struct encountered, ends with ";"
1276fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # state = 2 => var declaration encountered, ends with ";"
1277fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        # state = 3 => func declaration encountered, ends with "}"
1278d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1279d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if knownStatics is None:
1280d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            knownStatics = set()
1281d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        state = 0
1282d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        depth = 0
1283d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        blocks2 = []
1284fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner        skipTokens = False
12851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for b in self.blocks:
12861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if b.isDirective():
12871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                blocks2.append(b)
12881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            else:
1289d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                n = len(b.tokens)
1290d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                i = 0
1291fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                if skipTokens:
12921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    first = n
1293fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                else:
1294fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    first = 0
12951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                while i < n:
12961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    tok = b.tokens[i]
1297fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    tokid = tok.id
1298fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # If we are not looking for the start of a new
1299fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # type/var/func, then skip over tokens until
1300fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # we find our terminator, managing the depth of
1301fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # accolades as we go.
1302fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    if state > 0:
1303fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        terminator = False
1304fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        if tokid == '{':
13051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                            depth += 1
1306fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        elif tokid == '}':
13071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                            if depth > 0:
13081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                                depth -= 1
1309fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            if (depth == 0) and (state == 3):
1310fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                                terminator = True
1311fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        elif tokid == ';' and depth == 0:
1312fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            terminator = True
13131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1314fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        if terminator:
1315fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            # we found the terminator
13161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                            state = 0
1317fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            if skipTokens:
1318fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                                skipTokens = False
1319d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                first = i + 1
1320fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1321d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        i += 1
1322fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        continue
1323fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1324fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # Is it a new type definition, then start recording it
1325d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    if tok.id in ['struct', 'typedef', 'enum', 'union',
1326d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                  '__extension__']:
1327fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        state = 1
1328d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        i += 1
1329fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        continue
1330fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1331fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # Is it a variable or function definition. If so, first
1332fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # try to determine which type it is, and also extract
1333fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # its name.
1334fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    #
1335fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # We're going to parse the next tokens of the same block
1336fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # until we find a semi-column or a left parenthesis.
1337fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    #
1338fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # The semi-column corresponds to a variable definition,
1339fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # the left-parenthesis to a function definition.
1340fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    #
1341fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # We also assume that the var/func name is the last
1342fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    # identifier before the terminator.
1343fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    #
1344d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    j = i + 1
1345fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    ident = ""
1346fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    while j < n:
1347fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        tokid = b.tokens[j].id
1348fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        if tokid == '(':  # a function declaration
1349fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            state = 3
1350fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            break
1351d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        elif tokid == ';':  # a variable declaration
1352fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            state = 2
1353fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                            break
1354d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        if b.tokens[j].kind == TokenKind.IDENTIFIER:
1355d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                            ident = b.tokens[j].id
1356fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        j += 1
13571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1358fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    if j >= n:
1359fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # This can only happen when the declaration
1360fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # does not end on the current block (e.g. with
1361fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # a directive mixed inside it.
1362fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        #
1363fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # We will treat it as malformed because
1364fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # it's very hard to recover from this case
1365fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # without making our parser much more
1366fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # complex.
1367fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        #
1368d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        logging.debug("### skip unterminated static '%s'",
1369d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                      ident)
1370fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        break
1371fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1372fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    if ident in knownStatics:
1373d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        logging.debug("### keep var/func '%s': %s", ident,
1374d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                      repr(b.tokens[i:j]))
1375fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                    else:
1376fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        # We're going to skip the tokens for this declaration
1377d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        logging.debug("### skip var/func '%s': %s", ident,
1378d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                      repr(b.tokens[i:j]))
1379fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        if i > first:
1380d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                            blocks2.append(Block(b.tokens[first:i]))
1381fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner                        skipTokens = True
1382d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        first = n
1383fc2693110ee8a2ba22a445ad9855fbe9e118d439David 'Digit' Turner
1384d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    i += 1
13851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if i > first:
1387d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    # print "### final '%s'" % repr(b.tokens[first:i])
1388d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks2.append(Block(b.tokens[first:i]))
13891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
13901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        self.blocks = blocks2
13911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1392d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def replaceTokens(self, replacements):
1393d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Replace tokens according to the given dict."""
1394d32c8052fc2b2d3c5da344eb673df35d4a5bc052Martin Storsjo        for b in self.blocks:
1395fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes            made_change = False
1396d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if b.isInclude() is None:
1397d32c8052fc2b2d3c5da344eb673df35d4a5bc052Martin Storsjo                for tok in b.tokens:
1398d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    if tok.kind == TokenKind.IDENTIFIER:
1399d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        if tok.id in replacements:
1400d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                            tok.id = replacements[tok.id]
1401fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes                            made_change = True
1402fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes
1403d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if b.isDefine() and b.define_id in replacements:
1404d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    b.define_id = replacements[b.define_id]
1405d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    made_change = True
1406d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1407fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes            if made_change and b.isIf():
1408fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes                # Keep 'expr' in sync with 'tokens'.
1409fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes                b.expr = CppExpr(b.tokens)
1410d32c8052fc2b2d3c5da344eb673df35d4a5bc052Martin Storsjo
14111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1412d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef strip_space(s):
1413d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Strip out redundant space in a given string."""
1414d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1415d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # NOTE: It ought to be more clever to not destroy spaces in string tokens.
1416d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    replacements = {' . ': '.',
1417d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    ' [': '[',
1418d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    '[ ': '[',
1419d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    ' ]': ']',
1420d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    '( ': '(',
1421d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    ' )': ')',
1422d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    ' ,': ',',
1423d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    '# ': '#',
1424d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    ' ;': ';',
1425d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    '~ ': '~',
1426d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    ' -> ': '->'}
1427d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    result = s
1428d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    for r in replacements:
1429d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        result = result.replace(r, replacements[r])
1430d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1431d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # Remove the space between function name and the parenthesis.
1432d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    result = re.sub(r'(\w+) \(', r'\1(', result)
1433d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    return result
14341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
14351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1436d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baoclass BlockParser(object):
1437d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """A class that converts an input source file into a BlockList object."""
14381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1439d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def __init__(self, tokzer=None):
1440d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Initialize a block parser.
14411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1442d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        The input source is provided through a Tokenizer object.
1443d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """
1444d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._tokzer = tokzer
1445d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._parsed = False
14461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1447d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @property
1448d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def parsed(self):
1449d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self._parsed
14501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1451d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    @staticmethod
1452d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def _short_extent(extent):
1453d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return '%d:%d - %d:%d' % (extent.start.line, extent.start.column,
1454d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                  extent.end.line, extent.end.column)
1455d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1456d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def getBlocks(self, tokzer=None):
1457d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        """Return all the blocks parsed."""
1458d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1459d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        def consume_extent(i, tokens, extent=None, detect_change=False):
1460d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            """Return tokens that belong to the given extent.
1461d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1462d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            It parses all the tokens that follow tokens[i], until getting out
1463d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            of the extent. When detect_change is True, it may terminate early
1464d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            when detecting preprocessing directives inside the extent.
1465d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            """
1466d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1467d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            result = []
1468d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if extent is None:
1469d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                extent = tokens[i].cursor.extent
1470d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1471d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            while i < len(tokens) and tokens[i].location in extent:
1472d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                t = tokens[i]
1473d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if debugBlockParser:
1474d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    print ' ' * 2, t.id, t.kind, t.cursor.kind
1475d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if (detect_change and t.cursor.extent != extent and
1476d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    t.cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE):
1477d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    break
1478d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result.append(t)
1479d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                i += 1
1480d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return (i, result)
1481d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1482d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        def consume_line(i, tokens):
1483d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            """Return tokens that follow tokens[i] in the same line."""
1484d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            result = []
1485d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            line = tokens[i].location.line
1486d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            while i < len(tokens) and tokens[i].location.line == line:
1487d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if tokens[i].cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE:
1488d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    break
1489d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                result.append(tokens[i])
1490d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                i += 1
1491d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            return (i, result)
1492d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1493d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if tokzer is None:
1494d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            tokzer = self._tokzer
1495d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        tokens = tokzer.tokens
1496d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1497d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        blocks = []
1498d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        buf = []
1499d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        i = 0
1500d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1501d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        while i < len(tokens):
1502d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            t = tokens[i]
1503d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            cursor = t.cursor
1504d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1505d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if debugBlockParser:
1506d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                print ("%d: Processing [%s], kind=[%s], cursor=[%s], "
1507d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       "extent=[%s]" % (t.location.line, t.spelling, t.kind,
1508d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                        cursor.kind,
1509d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                        self._short_extent(cursor.extent)))
1510d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1511d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if cursor.kind == CursorKind.PREPROCESSING_DIRECTIVE:
1512d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if buf:
1513d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks.append(Block(buf))
1514d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf = []
1515d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1516d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                j = i
1517d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if j + 1 >= len(tokens):
1518d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    raise BadExpectedToken("### BAD TOKEN at %s" % (t.location))
1519d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                directive = tokens[j+1].id
1520d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1521d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if directive == 'define':
1522d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    if i+2 >= len(tokens):
1523d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        raise BadExpectedToken("### BAD TOKEN at %s" %
1524d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                               (tokens[i].location))
1525d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1526d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    # Skip '#' and 'define'.
1527d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    extent = tokens[i].cursor.extent
1528d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    i += 2
1529d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    id = ''
1530d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    # We need to separate the id from the remaining of
1531d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    # the line, especially for the function-like macro.
1532d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    if (i + 1 < len(tokens) and tokens[i+1].id == '(' and
1533d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        (tokens[i].location.column + len(tokens[i].spelling) ==
1534d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                         tokens[i+1].location.column)):
1535d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        while i < len(tokens):
1536d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                            id += tokens[i].id
1537d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                            if tokens[i].spelling == ')':
1538d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                i += 1
1539d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                break
1540d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                            i += 1
1541d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    else:
1542d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        id += tokens[i].id
1543d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        # Advance to the next token that follows the macro id
1544d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        i += 1
1545d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1546d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    (i, ret) = consume_extent(i, tokens, extent=extent)
1547d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks.append(Block(ret, directive=directive,
1548d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                        lineno=t.location.line, identifier=id))
1549d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1550d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                else:
1551d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    (i, ret) = consume_extent(i, tokens)
1552d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks.append(Block(ret[2:], directive=directive,
1553d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                        lineno=t.location.line))
1554d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1555d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif cursor.kind == CursorKind.INCLUSION_DIRECTIVE:
1556d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if buf:
1557d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks.append(Block(buf))
1558d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf = []
1559d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                directive = tokens[i+1].id
1560d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                (i, ret) = consume_extent(i, tokens)
15611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1562d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                blocks.append(Block(ret[2:], directive=directive,
1563d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                    lineno=t.location.line))
15641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1565d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif cursor.kind == CursorKind.VAR_DECL:
1566d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if buf:
1567d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks.append(Block(buf))
1568d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf = []
15691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1570d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                (i, ret) = consume_extent(i, tokens, detect_change=True)
1571d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf += ret
15721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1573d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif cursor.kind == CursorKind.FUNCTION_DECL:
1574d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                if buf:
1575d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    blocks.append(Block(buf))
1576d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                    buf = []
1577d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1578d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                (i, ret) = consume_extent(i, tokens, detect_change=True)
1579d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf += ret
15801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
15811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            else:
1582d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                (i, ret) = consume_line(i, tokens)
1583d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                buf += ret
15841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1585d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if buf:
1586d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            blocks.append(Block(buf))
15871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1588d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # _parsed=True indicates a successful parsing, although may result an
1589d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        # empty BlockList.
1590d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        self._parsed = True
15911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1592d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return BlockList(blocks)
15931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1594d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def parse(self, tokzer):
1595d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.getBlocks(tokzer)
15961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1597d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    def parseFile(self, path):
1598d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        return self.getBlocks(CppFileTokenizer(path))
15991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1601d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef test_block_parsing(lines, expected):
1602d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Helper method to test the correctness of BlockParser.parse."""
1603d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    blocks = BlockParser().parse(CppStringTokenizer('\n'.join(lines)))
16041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if len(blocks) != len(expected):
1605d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        raise BadExpectedToken("BlockParser.parse() returned '%s' expecting "
1606d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                               "'%s'" % (str(blocks), repr(expected)))
16071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for n in range(len(blocks)):
16081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if str(blocks[n]) != expected[n]:
1609d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            raise BadExpectedToken("BlockParser.parse()[%d] is '%s', "
1610d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                   "expecting '%s'" % (n, str(blocks[n]),
1611d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                                                       expected[n]))
1612d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
16131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef test_BlockParser():
1615d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_block_parsing(["#error hello"], ["#error hello"])
1616d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_block_parsing(["foo", "", "bar"], ["foo bar"])
1617d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1618d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # We currently cannot handle the following case with libclang properly.
1619d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # Fortunately it doesn't appear in current headers.
1620d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    # test_block_parsing(["foo", "  #  ", "bar"], ["foo", "bar"])
1621d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1622d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    test_block_parsing(["foo",
1623d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "  #  /* ahah */ if defined(__KERNEL__) /* more */",
1624d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                        "bar", "#endif"],
1625d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                       ["foo", "#ifdef __KERNEL__", "bar", "#endif"])
1626d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1627d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1628d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
1629d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
1630d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
1631d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####        B L O C K   L I S T   O P T I M I Z A T I O N                 #####
1632d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#####                                                                      #####
1633d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
1634d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao################################################################################
1635d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1636d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1637d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef remove_macro_defines(blocks, excludedMacros=None):
1638d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Remove macro definitions like #define <macroName>  ...."""
1639d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    if excludedMacros is None:
1640d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        excludedMacros = set()
16411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    result = []
16421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for b in blocks:
16431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        macroName = b.isDefine()
1644d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if macroName is None or macroName not in excludedMacros:
16451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result.append(b)
16461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return result
16481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1649d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1650d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef find_matching_endif(blocks, i):
1651d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Traverse the blocks to find out the matching #endif."""
1652d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    n = len(blocks)
16531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    depth = 1
16541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while i < n:
16551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if blocks[i].isDirective():
1656d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            dir_ = blocks[i].directive
1657d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if dir_ in ["if", "ifndef", "ifdef"]:
16581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                depth += 1
1659d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif depth == 1 and dir_ in ["else", "elif"]:
16601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                return i
1661d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif dir_ == "endif":
16621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                depth -= 1
16631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if depth == 0:
16641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return i
16651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        i += 1
16661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return i
16671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1668d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1669d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef optimize_if01(blocks):
1670d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Remove the code between #if 0 .. #endif in a list of CppBlocks."""
16711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    i = 0
16721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    n = len(blocks)
16731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    result = []
16741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while i < n:
16751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        j = i
16761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        while j < n and not blocks[j].isIf():
16771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            j += 1
16781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if j > i:
1679d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            logging.debug("appending lines %d to %d", blocks[i].lineno,
1680d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          blocks[j-1].lineno)
16811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result += blocks[i:j]
16821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if j >= n:
16831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break
16841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        expr = blocks[j].expr
1685d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        r = expr.toInt()
1686d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if r is None:
16871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result.append(blocks[j])
16881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            i = j + 1
16891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue
16901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if r == 0:
16921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            # if 0 => skip everything until the corresponding #endif
1693d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            j = find_matching_endif(blocks, j + 1)
16941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if j >= n:
16951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                # unterminated #if 0, finish here
16961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                break
1697d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            dir_ = blocks[j].directive
1698d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            if dir_ == "endif":
1699d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                logging.debug("remove 'if 0' .. 'endif' (lines %d to %d)",
1700d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                              blocks[i].lineno, blocks[j].lineno)
17011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                i = j + 1
1702d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif dir_ == "else":
17031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                # convert 'else' into 'if 1'
1704d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                logging.debug("convert 'if 0' .. 'else' into 'if 1' (lines %d "
1705d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                              "to %d)", blocks[i].lineno, blocks[j-1].lineno)
17061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                blocks[j].directive = "if"
1707d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                blocks[j].expr = CppExpr(CppStringTokenizer("1").tokens)
17081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                i = j
1709d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            elif dir_ == "elif":
17101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                # convert 'elif' into 'if'
1711dc1fb7000adb77c647f70428fd6ce224e3938220Elliott Hughes                logging.debug("convert 'if 0' .. 'elif' into 'if'")
17121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                blocks[j].directive = "if"
17131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                i = j
17141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            continue
17151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        # if 1 => find corresponding endif and remove/transform them
1717d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        k = find_matching_endif(blocks, j + 1)
17181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if k >= n:
17191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            # unterminated #if 1, finish here
1720dc1fb7000adb77c647f70428fd6ce224e3938220Elliott Hughes            logging.debug("unterminated 'if 1'")
17211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result += blocks[j+1:k]
17221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            break
17231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1724d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        dir_ = blocks[k].directive
1725d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        if dir_ == "endif":
1726d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            logging.debug("convert 'if 1' .. 'endif' (lines %d to %d)",
1727d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          blocks[j].lineno, blocks[k].lineno)
17281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result += optimize_if01(blocks[j+1:k])
1729d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            i = k + 1
1730d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        elif dir_ == "else":
17311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            # convert 'else' into 'if 0'
1732d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            logging.debug("convert 'if 1' .. 'else' (lines %d to %d)",
1733d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          blocks[j].lineno, blocks[k].lineno)
17341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result += optimize_if01(blocks[j+1:k])
17351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            blocks[k].directive = "if"
1736d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            blocks[k].expr = CppExpr(CppStringTokenizer("0").tokens)
17371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            i = k
1738d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        elif dir_ == "elif":
17391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            # convert 'elif' into 'if 0'
1740d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            logging.debug("convert 'if 1' .. 'elif' (lines %d to %d)",
1741d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao                          blocks[j].lineno, blocks[k].lineno)
17421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            result += optimize_if01(blocks[j+1:k])
1743d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao            blocks[k].expr = CppExpr(CppStringTokenizer("0").tokens)
17441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            i = k
17451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return result
17461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1747d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
1748d7db594b8d1dab36b711bd887a9dd21675c87243Tao Baodef test_optimizeAll():
17491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    text = """\
17501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 1
17511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  GOOD_1
17521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
17541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  BAD_2
17551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  BAD_3
17561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 1
17591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  GOOD_2
17601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else
17611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  BAD_4
17621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
17651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  BAD_5
17661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#else
17671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  GOOD_3
17681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
177040596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#if defined(__KERNEL__)
177140596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#define BAD_KERNEL
177240596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#endif
177340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
177440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
177540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#define X
177640596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#endif
177740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes
1778fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes#ifndef SIGRTMAX
1779fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes#define SIGRTMAX 123
1780fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes#endif /* SIGRTMAX */
1781fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes
17821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
17831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 1
17841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define  BAD_6
17851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
17861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif\
17871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project"""
17881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
17891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    expected = """\
17901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define GOOD_1
17911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define GOOD_2
17921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define GOOD_3
179340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#if !defined(__GLIBC__) || __GLIBC__ < 2
179440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#define X
179540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes#endif
1796fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes#ifndef __SIGRTMAX
1797fddbafdc0a63a1b4c5e9252719a913197a4eecfaElliott Hughes#define __SIGRTMAX 123
1798d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao#endif\
17991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project"""
18001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1801d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    out = utils.StringOutput()
1802d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    blocks = BlockParser().parse(CppStringTokenizer(text))
1803d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    blocks.replaceTokens(kernel_token_replacements)
1804d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    blocks.optimizeAll({"__KERNEL__": kCppUndefinedMacro})
1805d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    blocks.write(out)
18061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if out.get() != expected:
180740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        print "[FAIL]: macro optimization failed\n"
18081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print "<<<< expecting '",
18091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print expected,
1810d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao        print "'\n>>>> result '",
18111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print out.get(),
18121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        print "'\n----"
181340596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        global failure_count
181440596aa0054bcfa76148f55321bf4b979e2242beElliott Hughes        failure_count += 1
18151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
18171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdef runUnitTests():
1818d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    """Always run all unit tests for this program."""
18191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    test_CppTokenizer()
18201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    test_CppExpr()
18211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    test_optimizeAll()
18221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    test_BlockParser()
18231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1824d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao
182540596aa0054bcfa76148f55321bf4b979e2242beElliott Hughesfailure_count = 0
182640596aa0054bcfa76148f55321bf4b979e2242beElliott HughesrunUnitTests()
182740596aa0054bcfa76148f55321bf4b979e2242beElliott Hughesif failure_count != 0:
1828d7db594b8d1dab36b711bd887a9dd21675c87243Tao Bao    utils.panic("Unit tests failed in cpp.py.\n")
1829