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