1*1b3f573fSAndroid Build Coastguard Worker#! /usr/bin/env python3 2*1b3f573fSAndroid Build Coastguard Worker# 3*1b3f573fSAndroid Build Coastguard Worker# Protocol Buffers - Google's data interchange format 4*1b3f573fSAndroid Build Coastguard Worker# Copyright 2015 Google Inc. All rights reserved. 5*1b3f573fSAndroid Build Coastguard Worker# https://developers.google.com/protocol-buffers/ 6*1b3f573fSAndroid Build Coastguard Worker# 7*1b3f573fSAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 8*1b3f573fSAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are 9*1b3f573fSAndroid Build Coastguard Worker# met: 10*1b3f573fSAndroid Build Coastguard Worker# 11*1b3f573fSAndroid Build Coastguard Worker# * Redistributions of source code must retain the above copyright 12*1b3f573fSAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 13*1b3f573fSAndroid Build Coastguard Worker# * Redistributions in binary form must reproduce the above 14*1b3f573fSAndroid Build Coastguard Worker# copyright notice, this list of conditions and the following disclaimer 15*1b3f573fSAndroid Build Coastguard Worker# in the documentation and/or other materials provided with the 16*1b3f573fSAndroid Build Coastguard Worker# distribution. 17*1b3f573fSAndroid Build Coastguard Worker# * Neither the name of Google Inc. nor the names of its 18*1b3f573fSAndroid Build Coastguard Worker# contributors may be used to endorse or promote products derived from 19*1b3f573fSAndroid Build Coastguard Worker# this software without specific prior written permission. 20*1b3f573fSAndroid Build Coastguard Worker# 21*1b3f573fSAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*1b3f573fSAndroid Build Coastguard Worker# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*1b3f573fSAndroid Build Coastguard Worker# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24*1b3f573fSAndroid Build Coastguard Worker# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25*1b3f573fSAndroid Build Coastguard Worker# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*1b3f573fSAndroid Build Coastguard Worker# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27*1b3f573fSAndroid Build Coastguard Worker# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*1b3f573fSAndroid Build Coastguard Worker# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*1b3f573fSAndroid Build Coastguard Worker# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*1b3f573fSAndroid Build Coastguard Worker# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31*1b3f573fSAndroid Build Coastguard Worker# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*1b3f573fSAndroid Build Coastguard Worker 33*1b3f573fSAndroid Build Coastguard Worker"""PDDM - Poor Developers' Debug-able Macros 34*1b3f573fSAndroid Build Coastguard Worker 35*1b3f573fSAndroid Build Coastguard WorkerA simple markup that can be added in comments of source so they can then be 36*1b3f573fSAndroid Build Coastguard Workerexpanded out into code. Most of this could be done with CPP macros, but then 37*1b3f573fSAndroid Build Coastguard Workerdevelopers can't really step through them in the debugger, this way they are 38*1b3f573fSAndroid Build Coastguard Workerexpanded to the same code, but you can debug them. 39*1b3f573fSAndroid Build Coastguard Worker 40*1b3f573fSAndroid Build Coastguard WorkerAny file can be processed, but the syntax is designed around a C based compiler. 41*1b3f573fSAndroid Build Coastguard WorkerProcessed lines start with "//%". There are three types of sections you can 42*1b3f573fSAndroid Build Coastguard Workercreate: Text (left alone), Macro Definitions, and Macro Expansions. There is 43*1b3f573fSAndroid Build Coastguard Workerno order required between definitions and expansions, all definitions are read 44*1b3f573fSAndroid Build Coastguard Workerbefore any expansions are processed (thus, if desired, definitions can be put 45*1b3f573fSAndroid Build Coastguard Workerat the end of the file to keep them out of the way of the code). 46*1b3f573fSAndroid Build Coastguard Worker 47*1b3f573fSAndroid Build Coastguard WorkerMacro Definitions are started with "//%PDDM-DEFINE Name(args)" and all lines 48*1b3f573fSAndroid Build Coastguard Workerafterwards that start with "//%" are included in the definition. Multiple 49*1b3f573fSAndroid Build Coastguard Workermacros can be defined in one block by just using a another "//%PDDM-DEFINE" 50*1b3f573fSAndroid Build Coastguard Workerline to start the next macro. Optionally, a macro can be ended with 51*1b3f573fSAndroid Build Coastguard Worker"//%PDDM-DEFINE-END", this can be useful when you want to make it clear that 52*1b3f573fSAndroid Build Coastguard Workertrailing blank lines are included in the macro. You can also end a definition 53*1b3f573fSAndroid Build Coastguard Workerwith an expansion. 54*1b3f573fSAndroid Build Coastguard Worker 55*1b3f573fSAndroid Build Coastguard WorkerMacro Expansions are started by single lines containing 56*1b3f573fSAndroid Build Coastguard Worker"//%PDDM-EXPAND Name(args)" and then with "//%PDDM-EXPAND-END" or another 57*1b3f573fSAndroid Build Coastguard Workerexpansions. All lines in-between are replaced by the result of the expansion. 58*1b3f573fSAndroid Build Coastguard WorkerThe first line of the expansion is always a blank like just for readability. 59*1b3f573fSAndroid Build Coastguard Worker 60*1b3f573fSAndroid Build Coastguard WorkerExpansion itself is pretty simple, one macro can invoke another macro, but 61*1b3f573fSAndroid Build Coastguard Workeryou cannot nest the invoke of a macro in another macro (i.e. - can't do 62*1b3f573fSAndroid Build Coastguard Worker"foo(bar(a))", but you can define foo(a) and bar(b) where bar invokes foo() 63*1b3f573fSAndroid Build Coastguard Workerwithin its expansion. 64*1b3f573fSAndroid Build Coastguard Worker 65*1b3f573fSAndroid Build Coastguard WorkerWhen macros are expanded, the arg references can also add "$O" suffix to the 66*1b3f573fSAndroid Build Coastguard Workername (i.e. - "NAME$O") to specify an option to be applied. The options are: 67*1b3f573fSAndroid Build Coastguard Worker 68*1b3f573fSAndroid Build Coastguard Worker $S - Replace each character in the value with a space. 69*1b3f573fSAndroid Build Coastguard Worker $l - Lowercase the first letter of the value. 70*1b3f573fSAndroid Build Coastguard Worker $L - Lowercase the whole value. 71*1b3f573fSAndroid Build Coastguard Worker $u - Uppercase the first letter of the value. 72*1b3f573fSAndroid Build Coastguard Worker $U - Uppercase the whole value. 73*1b3f573fSAndroid Build Coastguard Worker 74*1b3f573fSAndroid Build Coastguard WorkerWithin a macro you can use ## to cause things to get joined together after 75*1b3f573fSAndroid Build Coastguard Workerexpansion (i.e. - "a##b" within a macro will become "ab"). 76*1b3f573fSAndroid Build Coastguard Worker 77*1b3f573fSAndroid Build Coastguard WorkerExample: 78*1b3f573fSAndroid Build Coastguard Worker 79*1b3f573fSAndroid Build Coastguard Worker int foo(MyEnum x) { 80*1b3f573fSAndroid Build Coastguard Worker switch (x) { 81*1b3f573fSAndroid Build Coastguard Worker //%PDDM-EXPAND case(Enum_Left, 1) 82*1b3f573fSAndroid Build Coastguard Worker //%PDDM-EXPAND case(Enum_Center, 2) 83*1b3f573fSAndroid Build Coastguard Worker //%PDDM-EXPAND case(Enum_Right, 3) 84*1b3f573fSAndroid Build Coastguard Worker //%PDDM-EXPAND-END 85*1b3f573fSAndroid Build Coastguard Worker } 86*1b3f573fSAndroid Build Coastguard Worker 87*1b3f573fSAndroid Build Coastguard Worker //%PDDM-DEFINE case(_A, _B) 88*1b3f573fSAndroid Build Coastguard Worker //% case _A: 89*1b3f573fSAndroid Build Coastguard Worker //% return _B; 90*1b3f573fSAndroid Build Coastguard Worker 91*1b3f573fSAndroid Build Coastguard Worker A macro ends at the start of the next one, or an optional %PDDM-DEFINE-END 92*1b3f573fSAndroid Build Coastguard Worker can be used to avoid adding extra blank lines/returns (or make it clear when 93*1b3f573fSAndroid Build Coastguard Worker it is desired). 94*1b3f573fSAndroid Build Coastguard Worker 95*1b3f573fSAndroid Build Coastguard Worker One macro can invoke another by simply using its name NAME(ARGS). You cannot 96*1b3f573fSAndroid Build Coastguard Worker nest an invoke inside another (i.e. - NAME1(NAME2(ARGS)) isn't supported). 97*1b3f573fSAndroid Build Coastguard Worker 98*1b3f573fSAndroid Build Coastguard Worker Within a macro you can use ## to cause things to get joined together after 99*1b3f573fSAndroid Build Coastguard Worker processing (i.e. - "a##b" within a macro will become "ab"). 100*1b3f573fSAndroid Build Coastguard Worker 101*1b3f573fSAndroid Build Coastguard Worker 102*1b3f573fSAndroid Build Coastguard Worker""" 103*1b3f573fSAndroid Build Coastguard Worker 104*1b3f573fSAndroid Build Coastguard Workerimport optparse 105*1b3f573fSAndroid Build Coastguard Workerimport os 106*1b3f573fSAndroid Build Coastguard Workerimport re 107*1b3f573fSAndroid Build Coastguard Workerimport sys 108*1b3f573fSAndroid Build Coastguard Worker 109*1b3f573fSAndroid Build Coastguard Worker 110*1b3f573fSAndroid Build Coastguard Worker# Regex for macro definition. 111*1b3f573fSAndroid Build Coastguard Worker_MACRO_RE = re.compile(r'(?P<name>\w+)\((?P<args>.*?)\)') 112*1b3f573fSAndroid Build Coastguard Worker# Regex for macro's argument definition. 113*1b3f573fSAndroid Build Coastguard Worker_MACRO_ARG_NAME_RE = re.compile(r'^\w+$') 114*1b3f573fSAndroid Build Coastguard Worker 115*1b3f573fSAndroid Build Coastguard Worker# Line inserted after each EXPAND. 116*1b3f573fSAndroid Build Coastguard Worker_GENERATED_CODE_LINE = ( 117*1b3f573fSAndroid Build Coastguard Worker '// This block of code is generated, do not edit it directly.' 118*1b3f573fSAndroid Build Coastguard Worker) 119*1b3f573fSAndroid Build Coastguard Worker 120*1b3f573fSAndroid Build Coastguard Worker 121*1b3f573fSAndroid Build Coastguard Workerdef _MacroRefRe(macro_names): 122*1b3f573fSAndroid Build Coastguard Worker # Takes in a list of macro names and makes a regex that will match invokes 123*1b3f573fSAndroid Build Coastguard Worker # of those macros. 124*1b3f573fSAndroid Build Coastguard Worker return re.compile(r'\b(?P<macro_ref>(?P<name>(%s))\((?P<args>.*?)\))' % 125*1b3f573fSAndroid Build Coastguard Worker '|'.join(macro_names)) 126*1b3f573fSAndroid Build Coastguard Worker 127*1b3f573fSAndroid Build Coastguard Worker 128*1b3f573fSAndroid Build Coastguard Workerdef _MacroArgRefRe(macro_arg_names): 129*1b3f573fSAndroid Build Coastguard Worker # Takes in a list of macro arg names and makes a regex that will match 130*1b3f573fSAndroid Build Coastguard Worker # uses of those args. 131*1b3f573fSAndroid Build Coastguard Worker return re.compile(r'\b(?P<name>(%s))(\$(?P<option>.))?\b' % 132*1b3f573fSAndroid Build Coastguard Worker '|'.join(macro_arg_names)) 133*1b3f573fSAndroid Build Coastguard Worker 134*1b3f573fSAndroid Build Coastguard Worker 135*1b3f573fSAndroid Build Coastguard Workerclass PDDMError(Exception): 136*1b3f573fSAndroid Build Coastguard Worker """Error thrown by pddm.""" 137*1b3f573fSAndroid Build Coastguard Worker 138*1b3f573fSAndroid Build Coastguard Worker def __init__(self, message="Error"): 139*1b3f573fSAndroid Build Coastguard Worker self.message = message 140*1b3f573fSAndroid Build Coastguard Worker super().__init__(self.message) 141*1b3f573fSAndroid Build Coastguard Worker 142*1b3f573fSAndroid Build Coastguard Worker 143*1b3f573fSAndroid Build Coastguard Workerclass MacroCollection(object): 144*1b3f573fSAndroid Build Coastguard Worker """Hold a set of macros and can resolve/expand them.""" 145*1b3f573fSAndroid Build Coastguard Worker 146*1b3f573fSAndroid Build Coastguard Worker def __init__(self, a_file=None): 147*1b3f573fSAndroid Build Coastguard Worker """Initializes the collection. 148*1b3f573fSAndroid Build Coastguard Worker 149*1b3f573fSAndroid Build Coastguard Worker Args: 150*1b3f573fSAndroid Build Coastguard Worker a_file: The file like stream to parse. 151*1b3f573fSAndroid Build Coastguard Worker 152*1b3f573fSAndroid Build Coastguard Worker Raises: 153*1b3f573fSAndroid Build Coastguard Worker PDDMError if there are any issues. 154*1b3f573fSAndroid Build Coastguard Worker """ 155*1b3f573fSAndroid Build Coastguard Worker self._macros = dict() 156*1b3f573fSAndroid Build Coastguard Worker if a_file: 157*1b3f573fSAndroid Build Coastguard Worker self.ParseInput(a_file) 158*1b3f573fSAndroid Build Coastguard Worker 159*1b3f573fSAndroid Build Coastguard Worker class MacroDefinition(object): 160*1b3f573fSAndroid Build Coastguard Worker """Holds a macro definition.""" 161*1b3f573fSAndroid Build Coastguard Worker 162*1b3f573fSAndroid Build Coastguard Worker def __init__(self, name, arg_names): 163*1b3f573fSAndroid Build Coastguard Worker self._name = name 164*1b3f573fSAndroid Build Coastguard Worker self._args = tuple(arg_names) 165*1b3f573fSAndroid Build Coastguard Worker self._body = '' 166*1b3f573fSAndroid Build Coastguard Worker self._needNewLine = False 167*1b3f573fSAndroid Build Coastguard Worker 168*1b3f573fSAndroid Build Coastguard Worker def AppendLine(self, line): 169*1b3f573fSAndroid Build Coastguard Worker if self._needNewLine: 170*1b3f573fSAndroid Build Coastguard Worker self._body += '\n' 171*1b3f573fSAndroid Build Coastguard Worker self._body += line 172*1b3f573fSAndroid Build Coastguard Worker self._needNewLine = not line.endswith('\n') 173*1b3f573fSAndroid Build Coastguard Worker 174*1b3f573fSAndroid Build Coastguard Worker @property 175*1b3f573fSAndroid Build Coastguard Worker def name(self): 176*1b3f573fSAndroid Build Coastguard Worker return self._name 177*1b3f573fSAndroid Build Coastguard Worker 178*1b3f573fSAndroid Build Coastguard Worker @property 179*1b3f573fSAndroid Build Coastguard Worker def args(self): 180*1b3f573fSAndroid Build Coastguard Worker return self._args 181*1b3f573fSAndroid Build Coastguard Worker 182*1b3f573fSAndroid Build Coastguard Worker @property 183*1b3f573fSAndroid Build Coastguard Worker def body(self): 184*1b3f573fSAndroid Build Coastguard Worker return self._body 185*1b3f573fSAndroid Build Coastguard Worker 186*1b3f573fSAndroid Build Coastguard Worker def ParseInput(self, a_file): 187*1b3f573fSAndroid Build Coastguard Worker """Consumes input extracting definitions. 188*1b3f573fSAndroid Build Coastguard Worker 189*1b3f573fSAndroid Build Coastguard Worker Args: 190*1b3f573fSAndroid Build Coastguard Worker a_file: The file like stream to parse. 191*1b3f573fSAndroid Build Coastguard Worker 192*1b3f573fSAndroid Build Coastguard Worker Raises: 193*1b3f573fSAndroid Build Coastguard Worker PDDMError if there are any issues. 194*1b3f573fSAndroid Build Coastguard Worker """ 195*1b3f573fSAndroid Build Coastguard Worker input_lines = a_file.read().splitlines() 196*1b3f573fSAndroid Build Coastguard Worker self.ParseLines(input_lines) 197*1b3f573fSAndroid Build Coastguard Worker 198*1b3f573fSAndroid Build Coastguard Worker def ParseLines(self, input_lines): 199*1b3f573fSAndroid Build Coastguard Worker """Parses list of lines. 200*1b3f573fSAndroid Build Coastguard Worker 201*1b3f573fSAndroid Build Coastguard Worker Args: 202*1b3f573fSAndroid Build Coastguard Worker input_lines: A list of strings of input to parse (no newlines on the 203*1b3f573fSAndroid Build Coastguard Worker strings). 204*1b3f573fSAndroid Build Coastguard Worker 205*1b3f573fSAndroid Build Coastguard Worker Raises: 206*1b3f573fSAndroid Build Coastguard Worker PDDMError if there are any issues. 207*1b3f573fSAndroid Build Coastguard Worker """ 208*1b3f573fSAndroid Build Coastguard Worker current_macro = None 209*1b3f573fSAndroid Build Coastguard Worker for line in input_lines: 210*1b3f573fSAndroid Build Coastguard Worker if line.startswith('PDDM-'): 211*1b3f573fSAndroid Build Coastguard Worker directive = line.split(' ', 1)[0] 212*1b3f573fSAndroid Build Coastguard Worker if directive == 'PDDM-DEFINE': 213*1b3f573fSAndroid Build Coastguard Worker name, args = self._ParseDefineLine(line) 214*1b3f573fSAndroid Build Coastguard Worker if self._macros.get(name): 215*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Attempt to redefine macro: "%s"' % line) 216*1b3f573fSAndroid Build Coastguard Worker current_macro = self.MacroDefinition(name, args) 217*1b3f573fSAndroid Build Coastguard Worker self._macros[name] = current_macro 218*1b3f573fSAndroid Build Coastguard Worker continue 219*1b3f573fSAndroid Build Coastguard Worker if directive == 'PDDM-DEFINE-END': 220*1b3f573fSAndroid Build Coastguard Worker if not current_macro: 221*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Got DEFINE-END directive without an active macro:' 222*1b3f573fSAndroid Build Coastguard Worker ' "%s"' % line) 223*1b3f573fSAndroid Build Coastguard Worker current_macro = None 224*1b3f573fSAndroid Build Coastguard Worker continue 225*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Hit a line with an unknown directive: "%s"' % line) 226*1b3f573fSAndroid Build Coastguard Worker 227*1b3f573fSAndroid Build Coastguard Worker if current_macro: 228*1b3f573fSAndroid Build Coastguard Worker current_macro.AppendLine(line) 229*1b3f573fSAndroid Build Coastguard Worker continue 230*1b3f573fSAndroid Build Coastguard Worker 231*1b3f573fSAndroid Build Coastguard Worker # Allow blank lines between macro definitions. 232*1b3f573fSAndroid Build Coastguard Worker if line.strip() == '': 233*1b3f573fSAndroid Build Coastguard Worker continue 234*1b3f573fSAndroid Build Coastguard Worker 235*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Hit a line that wasn\'t a directive and no open macro' 236*1b3f573fSAndroid Build Coastguard Worker ' definition: "%s"' % line) 237*1b3f573fSAndroid Build Coastguard Worker 238*1b3f573fSAndroid Build Coastguard Worker def _ParseDefineLine(self, input_line): 239*1b3f573fSAndroid Build Coastguard Worker assert input_line.startswith('PDDM-DEFINE') 240*1b3f573fSAndroid Build Coastguard Worker line = input_line[12:].strip() 241*1b3f573fSAndroid Build Coastguard Worker match = _MACRO_RE.match(line) 242*1b3f573fSAndroid Build Coastguard Worker # Must match full line 243*1b3f573fSAndroid Build Coastguard Worker if match is None or match.group(0) != line: 244*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Failed to parse macro definition: "%s"' % input_line) 245*1b3f573fSAndroid Build Coastguard Worker name = match.group('name') 246*1b3f573fSAndroid Build Coastguard Worker args_str = match.group('args').strip() 247*1b3f573fSAndroid Build Coastguard Worker args = [] 248*1b3f573fSAndroid Build Coastguard Worker if args_str: 249*1b3f573fSAndroid Build Coastguard Worker for part in args_str.split(','): 250*1b3f573fSAndroid Build Coastguard Worker arg = part.strip() 251*1b3f573fSAndroid Build Coastguard Worker if arg == '': 252*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Empty arg name in macro definition: "%s"' 253*1b3f573fSAndroid Build Coastguard Worker % input_line) 254*1b3f573fSAndroid Build Coastguard Worker if not _MACRO_ARG_NAME_RE.match(arg): 255*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Invalid arg name "%s" in macro definition: "%s"' 256*1b3f573fSAndroid Build Coastguard Worker % (arg, input_line)) 257*1b3f573fSAndroid Build Coastguard Worker if arg in args: 258*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Arg name "%s" used more than once in macro' 259*1b3f573fSAndroid Build Coastguard Worker ' definition: "%s"' % (arg, input_line)) 260*1b3f573fSAndroid Build Coastguard Worker args.append(arg) 261*1b3f573fSAndroid Build Coastguard Worker return (name, tuple(args)) 262*1b3f573fSAndroid Build Coastguard Worker 263*1b3f573fSAndroid Build Coastguard Worker def Expand(self, macro_ref_str): 264*1b3f573fSAndroid Build Coastguard Worker """Expands the macro reference. 265*1b3f573fSAndroid Build Coastguard Worker 266*1b3f573fSAndroid Build Coastguard Worker Args: 267*1b3f573fSAndroid Build Coastguard Worker macro_ref_str: String of a macro reference (i.e. foo(a, b)). 268*1b3f573fSAndroid Build Coastguard Worker 269*1b3f573fSAndroid Build Coastguard Worker Returns: 270*1b3f573fSAndroid Build Coastguard Worker The text from the expansion. 271*1b3f573fSAndroid Build Coastguard Worker 272*1b3f573fSAndroid Build Coastguard Worker Raises: 273*1b3f573fSAndroid Build Coastguard Worker PDDMError if there are any issues. 274*1b3f573fSAndroid Build Coastguard Worker """ 275*1b3f573fSAndroid Build Coastguard Worker match = _MACRO_RE.match(macro_ref_str) 276*1b3f573fSAndroid Build Coastguard Worker if match is None or match.group(0) != macro_ref_str: 277*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Failed to parse macro reference: "%s"' % macro_ref_str) 278*1b3f573fSAndroid Build Coastguard Worker if match.group('name') not in self._macros: 279*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('No macro named "%s".' % match.group('name')) 280*1b3f573fSAndroid Build Coastguard Worker return self._Expand(match, [], macro_ref_str) 281*1b3f573fSAndroid Build Coastguard Worker 282*1b3f573fSAndroid Build Coastguard Worker def _FormatStack(self, macro_ref_stack): 283*1b3f573fSAndroid Build Coastguard Worker result = '' 284*1b3f573fSAndroid Build Coastguard Worker for _, macro_ref in reversed(macro_ref_stack): 285*1b3f573fSAndroid Build Coastguard Worker result += '\n...while expanding "%s".' % macro_ref 286*1b3f573fSAndroid Build Coastguard Worker return result 287*1b3f573fSAndroid Build Coastguard Worker 288*1b3f573fSAndroid Build Coastguard Worker def _Expand(self, macro_ref_match, macro_stack, macro_ref_str=None): 289*1b3f573fSAndroid Build Coastguard Worker if macro_ref_str is None: 290*1b3f573fSAndroid Build Coastguard Worker macro_ref_str = macro_ref_match.group('macro_ref') 291*1b3f573fSAndroid Build Coastguard Worker name = macro_ref_match.group('name') 292*1b3f573fSAndroid Build Coastguard Worker for prev_name, prev_macro_ref in macro_stack: 293*1b3f573fSAndroid Build Coastguard Worker if name == prev_name: 294*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Found macro recursion, invoking "%s":%s' % 295*1b3f573fSAndroid Build Coastguard Worker (macro_ref_str, self._FormatStack(macro_stack))) 296*1b3f573fSAndroid Build Coastguard Worker macro = self._macros[name] 297*1b3f573fSAndroid Build Coastguard Worker args_str = macro_ref_match.group('args').strip() 298*1b3f573fSAndroid Build Coastguard Worker args = [] 299*1b3f573fSAndroid Build Coastguard Worker if args_str or len(macro.args): 300*1b3f573fSAndroid Build Coastguard Worker args = [x.strip() for x in args_str.split(',')] 301*1b3f573fSAndroid Build Coastguard Worker if len(args) != len(macro.args): 302*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Expected %d args, got: "%s".%s' % 303*1b3f573fSAndroid Build Coastguard Worker (len(macro.args), macro_ref_str, 304*1b3f573fSAndroid Build Coastguard Worker self._FormatStack(macro_stack))) 305*1b3f573fSAndroid Build Coastguard Worker # Replace args usages. 306*1b3f573fSAndroid Build Coastguard Worker result = self._ReplaceArgValues(macro, args, macro_ref_str, macro_stack) 307*1b3f573fSAndroid Build Coastguard Worker # Expand any macro invokes. 308*1b3f573fSAndroid Build Coastguard Worker new_macro_stack = macro_stack + [(name, macro_ref_str)] 309*1b3f573fSAndroid Build Coastguard Worker while True: 310*1b3f573fSAndroid Build Coastguard Worker eval_result = self._EvalMacrosRefs(result, new_macro_stack) 311*1b3f573fSAndroid Build Coastguard Worker # Consume all ## directives to glue things together. 312*1b3f573fSAndroid Build Coastguard Worker eval_result = eval_result.replace('##', '') 313*1b3f573fSAndroid Build Coastguard Worker if eval_result == result: 314*1b3f573fSAndroid Build Coastguard Worker break 315*1b3f573fSAndroid Build Coastguard Worker result = eval_result 316*1b3f573fSAndroid Build Coastguard Worker return result 317*1b3f573fSAndroid Build Coastguard Worker 318*1b3f573fSAndroid Build Coastguard Worker def _ReplaceArgValues(self, 319*1b3f573fSAndroid Build Coastguard Worker macro, arg_values, macro_ref_to_report, macro_stack): 320*1b3f573fSAndroid Build Coastguard Worker if len(arg_values) == 0: 321*1b3f573fSAndroid Build Coastguard Worker # Nothing to do 322*1b3f573fSAndroid Build Coastguard Worker return macro.body 323*1b3f573fSAndroid Build Coastguard Worker assert len(arg_values) == len(macro.args) 324*1b3f573fSAndroid Build Coastguard Worker args = dict(list(zip(macro.args, arg_values))) 325*1b3f573fSAndroid Build Coastguard Worker 326*1b3f573fSAndroid Build Coastguard Worker def _lookupArg(match): 327*1b3f573fSAndroid Build Coastguard Worker val = args[match.group('name')] 328*1b3f573fSAndroid Build Coastguard Worker opt = match.group('option') 329*1b3f573fSAndroid Build Coastguard Worker if opt: 330*1b3f573fSAndroid Build Coastguard Worker if opt == 'S': # Spaces for the length 331*1b3f573fSAndroid Build Coastguard Worker return ' ' * len(val) 332*1b3f573fSAndroid Build Coastguard Worker elif opt == 'l': # Lowercase first character 333*1b3f573fSAndroid Build Coastguard Worker if val: 334*1b3f573fSAndroid Build Coastguard Worker return val[0].lower() + val[1:] 335*1b3f573fSAndroid Build Coastguard Worker else: 336*1b3f573fSAndroid Build Coastguard Worker return val 337*1b3f573fSAndroid Build Coastguard Worker elif opt == 'L': # All Lowercase 338*1b3f573fSAndroid Build Coastguard Worker return val.lower() 339*1b3f573fSAndroid Build Coastguard Worker elif opt == 'u': # Uppercase first character 340*1b3f573fSAndroid Build Coastguard Worker if val: 341*1b3f573fSAndroid Build Coastguard Worker return val[0].upper() + val[1:] 342*1b3f573fSAndroid Build Coastguard Worker else: 343*1b3f573fSAndroid Build Coastguard Worker return val 344*1b3f573fSAndroid Build Coastguard Worker elif opt == 'U': # All Uppercase 345*1b3f573fSAndroid Build Coastguard Worker return val.upper() 346*1b3f573fSAndroid Build Coastguard Worker else: 347*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Unknown arg option "%s$%s" while expanding "%s".%s' 348*1b3f573fSAndroid Build Coastguard Worker % (match.group('name'), match.group('option'), 349*1b3f573fSAndroid Build Coastguard Worker macro_ref_to_report, 350*1b3f573fSAndroid Build Coastguard Worker self._FormatStack(macro_stack))) 351*1b3f573fSAndroid Build Coastguard Worker return val 352*1b3f573fSAndroid Build Coastguard Worker # Let the regex do the work! 353*1b3f573fSAndroid Build Coastguard Worker macro_arg_ref_re = _MacroArgRefRe(macro.args) 354*1b3f573fSAndroid Build Coastguard Worker return macro_arg_ref_re.sub(_lookupArg, macro.body) 355*1b3f573fSAndroid Build Coastguard Worker 356*1b3f573fSAndroid Build Coastguard Worker def _EvalMacrosRefs(self, text, macro_stack): 357*1b3f573fSAndroid Build Coastguard Worker macro_ref_re = _MacroRefRe(list(self._macros.keys())) 358*1b3f573fSAndroid Build Coastguard Worker 359*1b3f573fSAndroid Build Coastguard Worker def _resolveMacro(match): 360*1b3f573fSAndroid Build Coastguard Worker return self._Expand(match, macro_stack) 361*1b3f573fSAndroid Build Coastguard Worker return macro_ref_re.sub(_resolveMacro, text) 362*1b3f573fSAndroid Build Coastguard Worker 363*1b3f573fSAndroid Build Coastguard Worker 364*1b3f573fSAndroid Build Coastguard Workerclass SourceFile(object): 365*1b3f573fSAndroid Build Coastguard Worker """Represents a source file with PDDM directives in it.""" 366*1b3f573fSAndroid Build Coastguard Worker 367*1b3f573fSAndroid Build Coastguard Worker def __init__(self, a_file, import_resolver=None): 368*1b3f573fSAndroid Build Coastguard Worker """Initializes the file reading in the file. 369*1b3f573fSAndroid Build Coastguard Worker 370*1b3f573fSAndroid Build Coastguard Worker Args: 371*1b3f573fSAndroid Build Coastguard Worker a_file: The file to read in. 372*1b3f573fSAndroid Build Coastguard Worker import_resolver: a function that given a path will return a stream for 373*1b3f573fSAndroid Build Coastguard Worker the contents. 374*1b3f573fSAndroid Build Coastguard Worker 375*1b3f573fSAndroid Build Coastguard Worker Raises: 376*1b3f573fSAndroid Build Coastguard Worker PDDMError if there are any issues. 377*1b3f573fSAndroid Build Coastguard Worker """ 378*1b3f573fSAndroid Build Coastguard Worker self._sections = [] 379*1b3f573fSAndroid Build Coastguard Worker self._original_content = a_file.read() 380*1b3f573fSAndroid Build Coastguard Worker self._import_resolver = import_resolver 381*1b3f573fSAndroid Build Coastguard Worker self._processed_content = None 382*1b3f573fSAndroid Build Coastguard Worker 383*1b3f573fSAndroid Build Coastguard Worker class SectionBase(object): 384*1b3f573fSAndroid Build Coastguard Worker 385*1b3f573fSAndroid Build Coastguard Worker def __init__(self, first_line_num): 386*1b3f573fSAndroid Build Coastguard Worker self._lines = [] 387*1b3f573fSAndroid Build Coastguard Worker self._first_line_num = first_line_num 388*1b3f573fSAndroid Build Coastguard Worker 389*1b3f573fSAndroid Build Coastguard Worker def TryAppend(self, line, line_num): 390*1b3f573fSAndroid Build Coastguard Worker """Try appending a line. 391*1b3f573fSAndroid Build Coastguard Worker 392*1b3f573fSAndroid Build Coastguard Worker Args: 393*1b3f573fSAndroid Build Coastguard Worker line: The line to append. 394*1b3f573fSAndroid Build Coastguard Worker line_num: The number of the line. 395*1b3f573fSAndroid Build Coastguard Worker 396*1b3f573fSAndroid Build Coastguard Worker Returns: 397*1b3f573fSAndroid Build Coastguard Worker A tuple of (SUCCESS, CAN_ADD_MORE). If SUCCESS if False, the line 398*1b3f573fSAndroid Build Coastguard Worker wasn't append. If SUCCESS is True, then CAN_ADD_MORE is True/False to 399*1b3f573fSAndroid Build Coastguard Worker indicate if more lines can be added after this one. 400*1b3f573fSAndroid Build Coastguard Worker """ 401*1b3f573fSAndroid Build Coastguard Worker assert False, "subclass should have overridden" 402*1b3f573fSAndroid Build Coastguard Worker return (False, False) 403*1b3f573fSAndroid Build Coastguard Worker 404*1b3f573fSAndroid Build Coastguard Worker def HitEOF(self): 405*1b3f573fSAndroid Build Coastguard Worker """Called when the EOF was reached for for a given section.""" 406*1b3f573fSAndroid Build Coastguard Worker pass 407*1b3f573fSAndroid Build Coastguard Worker 408*1b3f573fSAndroid Build Coastguard Worker def BindMacroCollection(self, macro_collection): 409*1b3f573fSAndroid Build Coastguard Worker """Binds the chunk to a macro collection. 410*1b3f573fSAndroid Build Coastguard Worker 411*1b3f573fSAndroid Build Coastguard Worker Args: 412*1b3f573fSAndroid Build Coastguard Worker macro_collection: The collection to bind too. 413*1b3f573fSAndroid Build Coastguard Worker """ 414*1b3f573fSAndroid Build Coastguard Worker pass 415*1b3f573fSAndroid Build Coastguard Worker 416*1b3f573fSAndroid Build Coastguard Worker def Append(self, line): 417*1b3f573fSAndroid Build Coastguard Worker self._lines.append(line) 418*1b3f573fSAndroid Build Coastguard Worker 419*1b3f573fSAndroid Build Coastguard Worker @property 420*1b3f573fSAndroid Build Coastguard Worker def lines(self): 421*1b3f573fSAndroid Build Coastguard Worker return self._lines 422*1b3f573fSAndroid Build Coastguard Worker 423*1b3f573fSAndroid Build Coastguard Worker @property 424*1b3f573fSAndroid Build Coastguard Worker def num_lines_captured(self): 425*1b3f573fSAndroid Build Coastguard Worker return len(self._lines) 426*1b3f573fSAndroid Build Coastguard Worker 427*1b3f573fSAndroid Build Coastguard Worker @property 428*1b3f573fSAndroid Build Coastguard Worker def first_line_num(self): 429*1b3f573fSAndroid Build Coastguard Worker return self._first_line_num 430*1b3f573fSAndroid Build Coastguard Worker 431*1b3f573fSAndroid Build Coastguard Worker @property 432*1b3f573fSAndroid Build Coastguard Worker def first_line(self): 433*1b3f573fSAndroid Build Coastguard Worker if not self._lines: 434*1b3f573fSAndroid Build Coastguard Worker return '' 435*1b3f573fSAndroid Build Coastguard Worker return self._lines[0] 436*1b3f573fSAndroid Build Coastguard Worker 437*1b3f573fSAndroid Build Coastguard Worker @property 438*1b3f573fSAndroid Build Coastguard Worker def text(self): 439*1b3f573fSAndroid Build Coastguard Worker return '\n'.join(self.lines) + '\n' 440*1b3f573fSAndroid Build Coastguard Worker 441*1b3f573fSAndroid Build Coastguard Worker class TextSection(SectionBase): 442*1b3f573fSAndroid Build Coastguard Worker """Text section that is echoed out as is.""" 443*1b3f573fSAndroid Build Coastguard Worker 444*1b3f573fSAndroid Build Coastguard Worker def TryAppend(self, line, line_num): 445*1b3f573fSAndroid Build Coastguard Worker if line.startswith('//%PDDM'): 446*1b3f573fSAndroid Build Coastguard Worker return (False, False) 447*1b3f573fSAndroid Build Coastguard Worker self.Append(line) 448*1b3f573fSAndroid Build Coastguard Worker return (True, True) 449*1b3f573fSAndroid Build Coastguard Worker 450*1b3f573fSAndroid Build Coastguard Worker class ExpansionSection(SectionBase): 451*1b3f573fSAndroid Build Coastguard Worker """Section that is the result of an macro expansion.""" 452*1b3f573fSAndroid Build Coastguard Worker 453*1b3f573fSAndroid Build Coastguard Worker def __init__(self, first_line_num): 454*1b3f573fSAndroid Build Coastguard Worker SourceFile.SectionBase.__init__(self, first_line_num) 455*1b3f573fSAndroid Build Coastguard Worker self._macro_collection = None 456*1b3f573fSAndroid Build Coastguard Worker 457*1b3f573fSAndroid Build Coastguard Worker def TryAppend(self, line, line_num): 458*1b3f573fSAndroid Build Coastguard Worker if line.startswith('//%PDDM'): 459*1b3f573fSAndroid Build Coastguard Worker directive = line.split(' ', 1)[0] 460*1b3f573fSAndroid Build Coastguard Worker if directive == '//%PDDM-EXPAND': 461*1b3f573fSAndroid Build Coastguard Worker self.Append(line) 462*1b3f573fSAndroid Build Coastguard Worker return (True, True) 463*1b3f573fSAndroid Build Coastguard Worker if directive == '//%PDDM-EXPAND-END': 464*1b3f573fSAndroid Build Coastguard Worker assert self.num_lines_captured > 0 465*1b3f573fSAndroid Build Coastguard Worker return (True, False) 466*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Ran into directive ("%s", line %d) while in "%s".' % 467*1b3f573fSAndroid Build Coastguard Worker (directive, line_num, self.first_line)) 468*1b3f573fSAndroid Build Coastguard Worker # Eat other lines. 469*1b3f573fSAndroid Build Coastguard Worker return (True, True) 470*1b3f573fSAndroid Build Coastguard Worker 471*1b3f573fSAndroid Build Coastguard Worker def HitEOF(self): 472*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Hit the end of the file while in "%s".' % 473*1b3f573fSAndroid Build Coastguard Worker self.first_line) 474*1b3f573fSAndroid Build Coastguard Worker 475*1b3f573fSAndroid Build Coastguard Worker def BindMacroCollection(self, macro_collection): 476*1b3f573fSAndroid Build Coastguard Worker self._macro_collection = macro_collection 477*1b3f573fSAndroid Build Coastguard Worker 478*1b3f573fSAndroid Build Coastguard Worker @property 479*1b3f573fSAndroid Build Coastguard Worker def lines(self): 480*1b3f573fSAndroid Build Coastguard Worker captured_lines = SourceFile.SectionBase.lines.fget(self) 481*1b3f573fSAndroid Build Coastguard Worker directive_len = len('//%PDDM-EXPAND') 482*1b3f573fSAndroid Build Coastguard Worker result = [] 483*1b3f573fSAndroid Build Coastguard Worker for line in captured_lines: 484*1b3f573fSAndroid Build Coastguard Worker result.append(line) 485*1b3f573fSAndroid Build Coastguard Worker if self._macro_collection: 486*1b3f573fSAndroid Build Coastguard Worker # Always add a blank line, seems to read better. (If need be, add an 487*1b3f573fSAndroid Build Coastguard Worker # option to the EXPAND to indicate if this should be done.) 488*1b3f573fSAndroid Build Coastguard Worker result.extend([_GENERATED_CODE_LINE, '// clang-format off', '']) 489*1b3f573fSAndroid Build Coastguard Worker macro = line[directive_len:].strip() 490*1b3f573fSAndroid Build Coastguard Worker try: 491*1b3f573fSAndroid Build Coastguard Worker expand_result = self._macro_collection.Expand(macro) 492*1b3f573fSAndroid Build Coastguard Worker # Since expansions are line oriented, strip trailing whitespace 493*1b3f573fSAndroid Build Coastguard Worker # from the lines. 494*1b3f573fSAndroid Build Coastguard Worker lines = [x.rstrip() for x in expand_result.split('\n')] 495*1b3f573fSAndroid Build Coastguard Worker lines.append('// clang-format on') 496*1b3f573fSAndroid Build Coastguard Worker result.append('\n'.join(lines)) 497*1b3f573fSAndroid Build Coastguard Worker except PDDMError as e: 498*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('%s\n...while expanding "%s" from the section' 499*1b3f573fSAndroid Build Coastguard Worker ' that started:\n Line %d: %s' % 500*1b3f573fSAndroid Build Coastguard Worker (e.message, macro, 501*1b3f573fSAndroid Build Coastguard Worker self.first_line_num, self.first_line)) 502*1b3f573fSAndroid Build Coastguard Worker 503*1b3f573fSAndroid Build Coastguard Worker # Add the ending marker. 504*1b3f573fSAndroid Build Coastguard Worker if len(captured_lines) == 1: 505*1b3f573fSAndroid Build Coastguard Worker result.append('//%%PDDM-EXPAND-END %s' % 506*1b3f573fSAndroid Build Coastguard Worker captured_lines[0][directive_len:].strip()) 507*1b3f573fSAndroid Build Coastguard Worker else: 508*1b3f573fSAndroid Build Coastguard Worker result.append('//%%PDDM-EXPAND-END (%s expansions)' % 509*1b3f573fSAndroid Build Coastguard Worker len(captured_lines)) 510*1b3f573fSAndroid Build Coastguard Worker return result 511*1b3f573fSAndroid Build Coastguard Worker 512*1b3f573fSAndroid Build Coastguard Worker class DefinitionSection(SectionBase): 513*1b3f573fSAndroid Build Coastguard Worker """Section containing macro definitions""" 514*1b3f573fSAndroid Build Coastguard Worker 515*1b3f573fSAndroid Build Coastguard Worker def TryAppend(self, line, line_num): 516*1b3f573fSAndroid Build Coastguard Worker if not line.startswith('//%'): 517*1b3f573fSAndroid Build Coastguard Worker return (False, False) 518*1b3f573fSAndroid Build Coastguard Worker if line.startswith('//%PDDM'): 519*1b3f573fSAndroid Build Coastguard Worker directive = line.split(' ', 1)[0] 520*1b3f573fSAndroid Build Coastguard Worker if directive == "//%PDDM-EXPAND": 521*1b3f573fSAndroid Build Coastguard Worker return False, False 522*1b3f573fSAndroid Build Coastguard Worker if directive not in ('//%PDDM-DEFINE', '//%PDDM-DEFINE-END'): 523*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Ran into directive ("%s", line %d) while in "%s".' % 524*1b3f573fSAndroid Build Coastguard Worker (directive, line_num, self.first_line)) 525*1b3f573fSAndroid Build Coastguard Worker self.Append(line) 526*1b3f573fSAndroid Build Coastguard Worker return (True, True) 527*1b3f573fSAndroid Build Coastguard Worker 528*1b3f573fSAndroid Build Coastguard Worker def BindMacroCollection(self, macro_collection): 529*1b3f573fSAndroid Build Coastguard Worker if macro_collection: 530*1b3f573fSAndroid Build Coastguard Worker try: 531*1b3f573fSAndroid Build Coastguard Worker # Parse the lines after stripping the prefix. 532*1b3f573fSAndroid Build Coastguard Worker macro_collection.ParseLines([x[3:] for x in self.lines]) 533*1b3f573fSAndroid Build Coastguard Worker except PDDMError as e: 534*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('%s\n...while parsing section that started:\n' 535*1b3f573fSAndroid Build Coastguard Worker ' Line %d: %s' % 536*1b3f573fSAndroid Build Coastguard Worker (e.message, self.first_line_num, self.first_line)) 537*1b3f573fSAndroid Build Coastguard Worker 538*1b3f573fSAndroid Build Coastguard Worker class ImportDefinesSection(SectionBase): 539*1b3f573fSAndroid Build Coastguard Worker """Section containing an import of PDDM-DEFINES from an external file.""" 540*1b3f573fSAndroid Build Coastguard Worker 541*1b3f573fSAndroid Build Coastguard Worker def __init__(self, first_line_num, import_resolver): 542*1b3f573fSAndroid Build Coastguard Worker SourceFile.SectionBase.__init__(self, first_line_num) 543*1b3f573fSAndroid Build Coastguard Worker self._import_resolver = import_resolver 544*1b3f573fSAndroid Build Coastguard Worker 545*1b3f573fSAndroid Build Coastguard Worker def TryAppend(self, line, line_num): 546*1b3f573fSAndroid Build Coastguard Worker if not line.startswith('//%PDDM-IMPORT-DEFINES '): 547*1b3f573fSAndroid Build Coastguard Worker return (False, False) 548*1b3f573fSAndroid Build Coastguard Worker assert self.num_lines_captured == 0 549*1b3f573fSAndroid Build Coastguard Worker self.Append(line) 550*1b3f573fSAndroid Build Coastguard Worker return (True, False) 551*1b3f573fSAndroid Build Coastguard Worker 552*1b3f573fSAndroid Build Coastguard Worker def BindMacroCollection(self, macro_colletion): 553*1b3f573fSAndroid Build Coastguard Worker if not macro_colletion: 554*1b3f573fSAndroid Build Coastguard Worker return 555*1b3f573fSAndroid Build Coastguard Worker if self._import_resolver is None: 556*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Got an IMPORT-DEFINES without a resolver (line %d):' 557*1b3f573fSAndroid Build Coastguard Worker ' "%s".' % (self.first_line_num, self.first_line)) 558*1b3f573fSAndroid Build Coastguard Worker import_name = self.first_line.split(' ', 1)[1].strip() 559*1b3f573fSAndroid Build Coastguard Worker imported_file = self._import_resolver(import_name) 560*1b3f573fSAndroid Build Coastguard Worker if imported_file is None: 561*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Resolver failed to find "%s" (line %d):' 562*1b3f573fSAndroid Build Coastguard Worker ' "%s".' % 563*1b3f573fSAndroid Build Coastguard Worker (import_name, self.first_line_num, self.first_line)) 564*1b3f573fSAndroid Build Coastguard Worker try: 565*1b3f573fSAndroid Build Coastguard Worker imported_src_file = SourceFile(imported_file, self._import_resolver) 566*1b3f573fSAndroid Build Coastguard Worker imported_src_file._ParseFile() 567*1b3f573fSAndroid Build Coastguard Worker for section in imported_src_file._sections: 568*1b3f573fSAndroid Build Coastguard Worker section.BindMacroCollection(macro_colletion) 569*1b3f573fSAndroid Build Coastguard Worker except PDDMError as e: 570*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('%s\n...while importing defines:\n' 571*1b3f573fSAndroid Build Coastguard Worker ' Line %d: %s' % 572*1b3f573fSAndroid Build Coastguard Worker (e.message, self.first_line_num, self.first_line)) 573*1b3f573fSAndroid Build Coastguard Worker 574*1b3f573fSAndroid Build Coastguard Worker def _ParseFile(self): 575*1b3f573fSAndroid Build Coastguard Worker self._sections = [] 576*1b3f573fSAndroid Build Coastguard Worker lines = self._original_content.splitlines() 577*1b3f573fSAndroid Build Coastguard Worker cur_section = None 578*1b3f573fSAndroid Build Coastguard Worker for line_num, line in enumerate(lines, 1): 579*1b3f573fSAndroid Build Coastguard Worker if not cur_section: 580*1b3f573fSAndroid Build Coastguard Worker cur_section = self._MakeSection(line, line_num) 581*1b3f573fSAndroid Build Coastguard Worker was_added, accept_more = cur_section.TryAppend(line, line_num) 582*1b3f573fSAndroid Build Coastguard Worker if not was_added: 583*1b3f573fSAndroid Build Coastguard Worker cur_section = self._MakeSection(line, line_num) 584*1b3f573fSAndroid Build Coastguard Worker was_added, accept_more = cur_section.TryAppend(line, line_num) 585*1b3f573fSAndroid Build Coastguard Worker assert was_added 586*1b3f573fSAndroid Build Coastguard Worker if not accept_more: 587*1b3f573fSAndroid Build Coastguard Worker cur_section = None 588*1b3f573fSAndroid Build Coastguard Worker 589*1b3f573fSAndroid Build Coastguard Worker if cur_section: 590*1b3f573fSAndroid Build Coastguard Worker cur_section.HitEOF() 591*1b3f573fSAndroid Build Coastguard Worker 592*1b3f573fSAndroid Build Coastguard Worker def _MakeSection(self, line, line_num): 593*1b3f573fSAndroid Build Coastguard Worker if not line.startswith('//%PDDM'): 594*1b3f573fSAndroid Build Coastguard Worker section = self.TextSection(line_num) 595*1b3f573fSAndroid Build Coastguard Worker else: 596*1b3f573fSAndroid Build Coastguard Worker directive = line.split(' ', 1)[0] 597*1b3f573fSAndroid Build Coastguard Worker if directive == '//%PDDM-EXPAND': 598*1b3f573fSAndroid Build Coastguard Worker section = self.ExpansionSection(line_num) 599*1b3f573fSAndroid Build Coastguard Worker elif directive == '//%PDDM-DEFINE': 600*1b3f573fSAndroid Build Coastguard Worker section = self.DefinitionSection(line_num) 601*1b3f573fSAndroid Build Coastguard Worker elif directive == '//%PDDM-IMPORT-DEFINES': 602*1b3f573fSAndroid Build Coastguard Worker section = self.ImportDefinesSection(line_num, self._import_resolver) 603*1b3f573fSAndroid Build Coastguard Worker else: 604*1b3f573fSAndroid Build Coastguard Worker raise PDDMError('Unexpected line %d: "%s".' % (line_num, line)) 605*1b3f573fSAndroid Build Coastguard Worker self._sections.append(section) 606*1b3f573fSAndroid Build Coastguard Worker return section 607*1b3f573fSAndroid Build Coastguard Worker 608*1b3f573fSAndroid Build Coastguard Worker def ProcessContent(self, strip_expansion=False): 609*1b3f573fSAndroid Build Coastguard Worker """Processes the file contents.""" 610*1b3f573fSAndroid Build Coastguard Worker self._ParseFile() 611*1b3f573fSAndroid Build Coastguard Worker if strip_expansion: 612*1b3f573fSAndroid Build Coastguard Worker # Without a collection the expansions become blank, removing them. 613*1b3f573fSAndroid Build Coastguard Worker collection = None 614*1b3f573fSAndroid Build Coastguard Worker else: 615*1b3f573fSAndroid Build Coastguard Worker collection = MacroCollection() 616*1b3f573fSAndroid Build Coastguard Worker for section in self._sections: 617*1b3f573fSAndroid Build Coastguard Worker section.BindMacroCollection(collection) 618*1b3f573fSAndroid Build Coastguard Worker result = '' 619*1b3f573fSAndroid Build Coastguard Worker for section in self._sections: 620*1b3f573fSAndroid Build Coastguard Worker result += section.text 621*1b3f573fSAndroid Build Coastguard Worker self._processed_content = result 622*1b3f573fSAndroid Build Coastguard Worker 623*1b3f573fSAndroid Build Coastguard Worker @property 624*1b3f573fSAndroid Build Coastguard Worker def original_content(self): 625*1b3f573fSAndroid Build Coastguard Worker return self._original_content 626*1b3f573fSAndroid Build Coastguard Worker 627*1b3f573fSAndroid Build Coastguard Worker @property 628*1b3f573fSAndroid Build Coastguard Worker def processed_content(self): 629*1b3f573fSAndroid Build Coastguard Worker return self._processed_content 630*1b3f573fSAndroid Build Coastguard Worker 631*1b3f573fSAndroid Build Coastguard Worker 632*1b3f573fSAndroid Build Coastguard Workerdef main(args): 633*1b3f573fSAndroid Build Coastguard Worker usage = '%prog [OPTIONS] PATH ...' 634*1b3f573fSAndroid Build Coastguard Worker description = ( 635*1b3f573fSAndroid Build Coastguard Worker 'Processes PDDM directives in the given paths and write them back out.' 636*1b3f573fSAndroid Build Coastguard Worker ) 637*1b3f573fSAndroid Build Coastguard Worker parser = optparse.OptionParser(usage=usage, description=description) 638*1b3f573fSAndroid Build Coastguard Worker parser.add_option('--dry-run', 639*1b3f573fSAndroid Build Coastguard Worker default=False, action='store_true', 640*1b3f573fSAndroid Build Coastguard Worker help='Don\'t write back to the file(s), just report if the' 641*1b3f573fSAndroid Build Coastguard Worker ' contents needs an update and exit with a value of 1.') 642*1b3f573fSAndroid Build Coastguard Worker parser.add_option('--verbose', 643*1b3f573fSAndroid Build Coastguard Worker default=False, action='store_true', 644*1b3f573fSAndroid Build Coastguard Worker help='Reports is a file is already current.') 645*1b3f573fSAndroid Build Coastguard Worker parser.add_option('--collapse', 646*1b3f573fSAndroid Build Coastguard Worker default=False, action='store_true', 647*1b3f573fSAndroid Build Coastguard Worker help='Removes all the generated code.') 648*1b3f573fSAndroid Build Coastguard Worker opts, extra_args = parser.parse_args(args) 649*1b3f573fSAndroid Build Coastguard Worker 650*1b3f573fSAndroid Build Coastguard Worker if not extra_args: 651*1b3f573fSAndroid Build Coastguard Worker parser.error('Need at least one file to process') 652*1b3f573fSAndroid Build Coastguard Worker 653*1b3f573fSAndroid Build Coastguard Worker result = 0 654*1b3f573fSAndroid Build Coastguard Worker for a_path in extra_args: 655*1b3f573fSAndroid Build Coastguard Worker if not os.path.exists(a_path): 656*1b3f573fSAndroid Build Coastguard Worker sys.stderr.write('ERROR: File not found: %s\n' % a_path) 657*1b3f573fSAndroid Build Coastguard Worker return 100 658*1b3f573fSAndroid Build Coastguard Worker 659*1b3f573fSAndroid Build Coastguard Worker def _ImportResolver(name): 660*1b3f573fSAndroid Build Coastguard Worker # resolve based on the file being read. 661*1b3f573fSAndroid Build Coastguard Worker a_dir = os.path.dirname(a_path) 662*1b3f573fSAndroid Build Coastguard Worker import_path = os.path.join(a_dir, name) 663*1b3f573fSAndroid Build Coastguard Worker if not os.path.exists(import_path): 664*1b3f573fSAndroid Build Coastguard Worker return None 665*1b3f573fSAndroid Build Coastguard Worker return open(import_path, 'r') 666*1b3f573fSAndroid Build Coastguard Worker 667*1b3f573fSAndroid Build Coastguard Worker with open(a_path, 'r') as f: 668*1b3f573fSAndroid Build Coastguard Worker src_file = SourceFile(f, _ImportResolver) 669*1b3f573fSAndroid Build Coastguard Worker 670*1b3f573fSAndroid Build Coastguard Worker try: 671*1b3f573fSAndroid Build Coastguard Worker src_file.ProcessContent(strip_expansion=opts.collapse) 672*1b3f573fSAndroid Build Coastguard Worker except PDDMError as e: 673*1b3f573fSAndroid Build Coastguard Worker sys.stderr.write('ERROR: %s\n...While processing "%s"\n' % 674*1b3f573fSAndroid Build Coastguard Worker (e.message, a_path)) 675*1b3f573fSAndroid Build Coastguard Worker return 101 676*1b3f573fSAndroid Build Coastguard Worker 677*1b3f573fSAndroid Build Coastguard Worker if src_file.processed_content != src_file.original_content: 678*1b3f573fSAndroid Build Coastguard Worker if not opts.dry_run: 679*1b3f573fSAndroid Build Coastguard Worker print('Updating for "%s".' % a_path) 680*1b3f573fSAndroid Build Coastguard Worker with open(a_path, 'w') as f: 681*1b3f573fSAndroid Build Coastguard Worker f.write(src_file.processed_content) 682*1b3f573fSAndroid Build Coastguard Worker else: 683*1b3f573fSAndroid Build Coastguard Worker # Special result to indicate things need updating. 684*1b3f573fSAndroid Build Coastguard Worker print('Update needed for "%s".' % a_path) 685*1b3f573fSAndroid Build Coastguard Worker result = 1 686*1b3f573fSAndroid Build Coastguard Worker elif opts.verbose: 687*1b3f573fSAndroid Build Coastguard Worker print('No update for "%s".' % a_path) 688*1b3f573fSAndroid Build Coastguard Worker 689*1b3f573fSAndroid Build Coastguard Worker return result 690*1b3f573fSAndroid Build Coastguard Worker 691*1b3f573fSAndroid Build Coastguard Worker 692*1b3f573fSAndroid Build Coastguard Workerif __name__ == '__main__': 693*1b3f573fSAndroid Build Coastguard Worker sys.exit(main(sys.argv[1:])) 694