diff --git a/README.md b/README.md index 7c812d5..53aedbf 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ set the options of the preprocessor: * resume: Return after a file is preprocessed and can preprocess a next file if true. Default is false * save: Save preprocessed code if true. Default is true * overload: Any defines added to the preprocessor will overload existing defines. Default is false -* quiet: no warning about ununderstood directives or missing #indef +* quiet: no warning about not understood directives or missing #indef ```python pypreprocessor.input = 'inputFile.py' diff --git a/pypreprocessor/__init__.py b/pypreprocessor/__init__.py index 3373ee9..04542fe 100644 --- a/pypreprocessor/__init__.py +++ b/pypreprocessor/__init__.py @@ -3,7 +3,7 @@ __author__ = 'Evan Plaice' __coauthor__ = 'Hendi O L, Epikem, Laurent Pinson' -__version__ = '0.8' +__version__ = '1.0' import sys import os @@ -20,17 +20,19 @@ def append(self, var): class preprocessor: + __overloaded = [] + defines = customDict() + def __init__(self, inFile=sys.argv[0], outFile='', defines={}, removeMeta=False, escapeChar=None, mode=None, escape='#', run=True, resume=False, save=True, overload=True, quiet=False): # public variables - self.defines = customDict() - #support for <=0.7.7 + # support for <=0.7.7 if isinstance(defines, collections.Sequence): for x in defines: - self.define(x) + self.define(*x.split(':')) else: - for x,y in defines: + for x,y in defines.items(): self.define(x,y) self.input = inFile self.output = outFile @@ -89,12 +91,16 @@ def deprecation(message): def __reset_internal(self): self.__linenum = 0 self.__excludeblock = False - self.__ifblocks = [] # contains the evaluated if conditions - self.__ifconditions = [] # contains the if conditions + # contains the evaluated if conditions + # due to the introduction of #elif, elements of __ifblocks are duos of boolean + # the 1st is the evaluation of the current #if or #elif or #else + # the 2nd indicates if at least one #if or #elif was True in the whole #if/#endif block + self.__ifblocks = [] + # contains the if conditions + self.__ifconditions = [] self.__outputBuffer = '' self.__overloaded = list(self.defines.keys()) if self.overload else [] - def define(self, name, val=True): """ Adds variable definition to the store as expected from a #define directive. @@ -164,7 +170,7 @@ def __validate_ifs(self): """ # no ifs mean we pass else check all ifs are True - return not self.__ifblocks or all(self.__ifblocks) + return not self.__ifblocks or all(x[0] for x in self.__ifblocks) def __is_directive(self, line, directive, *size): """ @@ -243,41 +249,43 @@ def lexer(self, line): elif self.__is_directive(line, 'ifdefnot', 2) or \ self.__is_directive(line, 'ifnotdef', 2) or \ self.__is_directive(line, 'ifndef', 2): - self.__ifblocks.append(not self.__is_defined(line.split()[1])) + _check = not self.__is_defined(line.split()[1]) + self.__ifblocks.append([ _check, _check]) self.__ifconditions.append(line.split()[1]) elif self.__is_directive(line, 'ifdef', 2): - self.__ifblocks.append(self.__is_defined(line.split()[1])) + _check = self.__is_defined(line.split()[1]) + self.__ifblocks.append([ _check, _check]) self.__ifconditions.append(line.split()[1]) elif self.__is_directive(line, 'if'): - self.__ifblocks.append(self.__evaluate_if(' '.join(line.split()[1:]))) + _check = self.__evaluate_if(' '.join(line.split()[1:])) + self.__ifblocks.append([ _check, _check]) self.__ifconditions.append(' '.join(line.split()[1:])) # since in version <=0.7.7, it didn't handle #if it should be #elseifdef instead. # kept elseif with 2 elements for retro-compatibility (equivalent to #elseifdef). elif self.__is_directive(line, 'elseif') or \ self.__is_directive(line, 'elif'): - # do else - self.__ifblocks[-1] = not self.__ifblocks[-1] - # do if + _cur, _whole = self.__ifblocks[-1] if len(line.split()) == 2: #old behaviour - self.__ifblocks[-1] = self.__is_defined(line.split()[1]) + _check = self.__is_defined(line.split()[1]) else: #new behaviour - self.__ifblocks[-1] = self.__evaluate_if(' '.join(line.split()[1:])) - self.__ifconditions.append(' '.join(line.split()[1:])) + _check = self.__evaluate_if(' '.join(line.split()[1:])) + self.__ifblocks[-1]=[ not _whole and _check, _whole or _check ] + self.__ifconditions[-1]=' '.join(line.split()[1:]) elif self.__is_directive(line, 'elseifdef', 2): - # do else - self.__ifblocks[-1] = not self.__ifblocks[-1] - # do if - self.__ifblocks[-1]=self.__is_defined(line.split()[1]) - self.__ifconditions.append(' '.join(line.split()[1:])) + _cur, _whole = self.__ifblocks[-1] + _check = self.__is_defined(line.split()[1]) + self.__ifblocks[-1]=[ not _whole and _check, _whole or _check ] + self.__ifconditions[-1]=' '.join(line.split()[1:]) elif self.__is_directive(line, 'else', 1): - self.__ifblocks[-1] = not self.__ifblocks[-1] #opposite of last if + _cur, _whole = self.__ifblocks[-1] + self.__ifblocks[-1] = [not _whole, not _whole] #opposite of the whole if/elif block elif self.__is_directive(line, 'endififdef', 2): # do endif @@ -299,19 +307,17 @@ def lexer(self, line): except ValueError as VE: number = 1 - if len(self.__ifconditions) >= number: - for i in range(0, number): + try: + while number: self.__ifblocks.pop(-1) self.__ifconditions.pop(-1) - else: + number-=1 + except: if not self.quiet: print('Warning trying to remove more blocks than present', self.input, self.__linenum) - self.__ifblocks = [] - self.__ifconditions = [] else: - # unknown directive or comment # escapechar + space ==> comment # starts with #!/ ==> shebang # else print warning diff --git a/pypreprocessor/__main__.py b/pypreprocessor/__main__.py index 437f87b..0ecd8ee 100644 --- a/pypreprocessor/__main__.py +++ b/pypreprocessor/__main__.py @@ -8,30 +8,26 @@ python -m """+__package__+""" table.json --escape #@ -d NUM:4 ID:1 """, formatter_class=argparse.RawDescriptionHelpFormatter, - usage=' python -m '+__package__+' input [output] [-h] [-r] [-m] [-e ESCAPE] [-d [DEFINE ...]]', + usage=' python -m '+__package__+' input [output] [-h] [-r] [-m] [-e ESCAPE] [-o] [-q] [-d [DEFINE ...]]', ) -parser.add_argument("-r", "--run", help="Run on the fly", +parser.add_argument("-r", "--run", help="run on the fly", action='store_true', default=False) parser.add_argument("-m", "--removeMeta", help="remove meta lines from the output", action='store_true', default=False) parser.add_argument("-e", "--escape", help="define the escape sequence to use. Default is #") -parser.add_argument("-d", "--define", help="list of variable to define", nargs='*') +parser.add_argument("-d", "--define", help="list of constants to define", nargs='*', default=[]) parser.add_argument("-o", "--overload", help="overload variable definition in the file by those \ provided by --define", action='store_true', default=False) -parser.add_argument("-q", "--quiet", help="No warning on ununderstable directives and missign ending", +parser.add_argument("-q", "--quiet", help="No warning on not understood directives and missign ending", action='store_true', default=False) parser.add_argument("input", help="input file.") parser.add_argument("output", nargs='?', help="output file. Default is _out.") args = parser.parse_args() -p=preprocessor(inFile=args.input, mode=None, removeMeta=args.removeMeta, escapeChar=None, +p=preprocessor(inFile=args.input, defines=args.define, mode=None, removeMeta=args.removeMeta, escapeChar=None, run=args.run, resume=False, save=True, overload=args.overload, quiet=args.quiet) if args.output: p.define = args.output -if args.define: - for elem in args.define: - p.define(*elem.split(':')) - self.__reset_internal() # not very pythonic if args.escape: p.escape = args.escape