From 917cd07a748dd236c7f2c95ae8e28fd8f6afccea Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 13 Jun 2018 11:17:06 +0200 Subject: [PATCH] css: deduplicate parser code in the CSS preprocessor. No change in the output (which was desired). --- css/postprocess.py | 179 ++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 100 deletions(-) diff --git a/css/postprocess.py b/css/postprocess.py index 2aa7df30..a0d58003 100755 --- a/css/postprocess.py +++ b/css/postprocess.py @@ -45,12 +45,82 @@ def postprocess(files, process_imports, out_file): basename, ext = os.path.splitext(files[0]) out_file = basename + ".compiled" + ext - with open(out_file, mode='w') as out: - variables = {} - imported_files = [] - + variables = {} + imported_files = [] + def parse(f): + nonlocal variables, imported_files not_just_variable_declarations = False + in_variable_declarations = False + in_comment = False + for line in f: + # In comment and the comment is not ending yet, ignore + if in_comment: + if comment_end_rx.match(line): + in_comment = False + continue + + # Import statement: add the file to additionally processed files + # unless it's disabled + match = import_rx.match(line) + if match: + if process_imports: + imported_files += [match['file']] + continue + + # Variable use, replace with actual value + # TODO: more variables on the same line? + match = variable_use_rx.match(line) + if match and match['key'] in variables: + out.write(match['before']) + out.write(variables[match['key']]) + out.write(match['after']) + out.write("\n") + continue + + # Opening brace of variable declaration block + match = opening_brace_rx.match(line) + if match: + in_variable_declarations = True + continue + + # Variable declaration + match = variable_declaration_rx.match(line) + if match and in_variable_declarations: + variables[match['key']] = match['value'] + continue + + # Comment or empty line, ignore + if comment_rx.match(line): + continue + + # Comment start line, ignore this and the next lines + if comment_start_rx.match(line): + in_comment = True + continue + + # Closing brace of variable declaration block. If it was not just + # variable declarations, put the closing brace to the output as + # well. + match = closing_brace_rx.match(line) + if match and in_variable_declarations: + if not_just_variable_declarations: out.write("}\n") + in_variable_declarations = False + continue + + # If inside variable declaration block, include also the opening + # brace and remeber to put the closing brace there as well + if in_variable_declarations: + out.write(":root {\n") + not_just_variable_declarations = True + + # Something else, copy verbatim to the output. Strip the trailing + # comment, if there, to save some bytes. + if line.rstrip().endswith('*/'): + out.write(line[:line.rindex('/*')].rstrip() + '\n') + else: + out.write(line) + with open(out_file, mode='w') as out: # Put a helper comment and a license blob on top out.write("""/* Generated using `./postprocess.py {}`. Do not edit. */ @@ -80,105 +150,14 @@ def postprocess(files, process_imports, out_file): """.format(' '.join(sys.argv[1:]))) # Parse the top-level file - with open(files[0]) as f: - in_variable_declarations = False - in_comment = False - for line in f: - # In comment and the comment is not ending yet, ignore - if in_comment: - if comment_end_rx.match(line): - in_comment = False - continue - - # Import statement: add the file to additionally processed - # files unless it's disabled - match = import_rx.match(line) - if match: - if process_imports: - imported_files += [match['file']] - continue - - # Opening brace of variable declaration block - match = opening_brace_rx.match(line) - if match: - in_variable_declarations = True - continue - - # Variable declaration - match = variable_declaration_rx.match(line) - if match and in_variable_declarations: - variables[match['key']] = match['value'] - continue - - # Comment or empty line, ignore - if comment_rx.match(line): - continue - - # Comment start line, ignore this and the next lines - if comment_start_rx.match(line): - in_comment = True - continue - - # Closing brace of variable declaration block. If it was not - # just variable declarations, put the closing brace to the - # output as well. - match = closing_brace_rx.match(line) - if match and in_variable_declarations: - if not_just_variable_declarations: out.write("}\n") - in_variable_declarations = False - continue - - # Something else, copy verbatim to the output. If inside - # variable declaration block, include also the opening brace - # and remeber to put the closing brace there as well - if in_variable_declarations: - out.write(":root {\n") - not_just_variable_declarations = True - - # Strip the trailing comment, if there, to save some bytes - if line.rstrip().endswith('*/'): - out.write(line[:line.rindex('/*')]) - else: - out.write(line) - - # Now open the imported files and replace variables + with open(files[0]) as f: parse(f) + + # Now open the imported files and parse them as well. Not doing any + # recursive parsing. for file in imported_files + files[1:]: out.write('\n') - with open(file) as f: - in_comment = False - for line in f: - # In comment and the comment is not ending yet, ignore - if in_comment: - if comment_end_rx.match(line): - in_comment = False - continue - - # Variable use, replace with actual value - # TODO: more variables on the same line? - match = variable_use_rx.match(line) - if match and match['key'] in variables: - out.write(match['before']) - out.write(variables[match['key']]) - out.write(match['after']) - out.write("\n") - continue - - # Comment or empty line, ignore - if comment_rx.match(line): - continue - - # Comment start line, ignore this and the next lines - if comment_start_rx.match(line): - in_comment = True - continue - - # Something else, copy verbatim to the output. Strip the - # trailing comment, if there, to save some bytes - if line.rstrip().endswith('*/'): - out.write(line[:line.rindex('/*')].rstrip() + '\n') - else: - out.write(line) + with open(file) as f: parse(f) return 0 -- 2.30.2