#! /usr/bin/env python3 # # Protocol Buffers - Google's data interchange format # Copyright 2015 Google Inc. All rights reserved. # https://developers.google.com/protocol-buffers/ # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """PDDM - Poor Developers' Debug-able Macros A simple markup that can be added in comments of source so they can then be expanded out into code. Most of this could be done with CPP macros, but then developers can't really step through them in the debugger, this way they are expanded to the same code, but you can debug them. Any file can be processed, but the syntax is designed around a C based compiler. Processed lines start with "//%". There are three types of sections you can create: Text (left alone), Macro Definitions, and Macro Expansions. There is no order required between definitions and expansions, all definitions are read before any expansions are processed (thus, if desired, definitions can be put at the end of the file to keep them out of the way of the code). Macro Definitions are started with "//%PDDM-DEFINE Name(args)" and all lines afterwards that start with "//%" are included in the definition. Multiple macros can be defined in one block by just using a another "//%PDDM-DEFINE" line to start the next macro. Optionally, a macro can be ended with "//%PDDM-DEFINE-END", this can be useful when you want to make it clear that trailing blank lines are included in the macro. You can also end a definition with an expansion. Macro Expansions are started by single lines containing "//%PDDM-EXPAND Name(args)" and then with "//%PDDM-EXPAND-END" or another expansions. All lines in-between are replaced by the result of the expansion. The first line of the expansion is always a blank like just for readability. Expansion itself is pretty simple, one macro can invoke another macro, but you cannot nest the invoke of a macro in another macro (i.e. - can't do "foo(bar(a))", but you can define foo(a) and bar(b) where bar invokes foo() within its expansion. When macros are expanded, the arg references can also add "$O" suffix to the name (i.e. - "NAME$O") to specify an option to be applied. The options are: $S - Replace each character in the value with a space. $l - Lowercase the first letter of the value. $L - Lowercase the whole value. $u - Uppercase the first letter of the value. $U - Uppercase the whole value. Within a macro you can use ## to cause things to get joined together after expansion (i.e. - "a##b" within a macro will become "ab"). Example: int foo(MyEnum x) { switch (x) { //%PDDM-EXPAND case(Enum_Left, 1) //%PDDM-EXPAND case(Enum_Center, 2) //%PDDM-EXPAND case(Enum_Right, 3) //%PDDM-EXPAND-END } //%PDDM-DEFINE case(_A, _B) //% case _A: //% return _B; A macro ends at the start of the next one, or an optional %PDDM-DEFINE-END can be used to avoid adding extra blank lines/returns (or make it clear when it is desired). One macro can invoke another by simply using its name NAME(ARGS). You cannot nest an invoke inside another (i.e. - NAME1(NAME2(ARGS)) isn't supported). Within a macro you can use ## to cause things to get joined together after processing (i.e. - "a##b" within a macro will become "ab"). """ import optparse import os import re import sys # Regex for macro definition. _MACRO_RE = re.compile(r'(?P\w+)\((?P.*?)\)') # Regex for macro's argument definition. _MACRO_ARG_NAME_RE = re.compile(r'^\w+$') # Line inserted after each EXPAND. _GENERATED_CODE_LINE = ( '// This block of code is generated, do not edit it directly.' ) def _MacroRefRe(macro_names): # Takes in a list of macro names and makes a regex that will match invokes # of those macros. return re.compile(r'\b(?P(?P(%s))\((?P.*?)\))' % '|'.join(macro_names)) def _MacroArgRefRe(macro_arg_names): # Takes in a list of macro arg names and makes a regex that will match # uses of those args. return re.compile(r'\b(?P(%s))(\$(?P