Skip to content

Commit

Permalink
Add ignore tag to the match.py script
Browse files Browse the repository at this point in the history
  • Loading branch information
kswiecicki committed Nov 8, 2023
1 parent 4a84470 commit eedc362
Showing 1 changed file with 118 additions and 57 deletions.
175 changes: 118 additions & 57 deletions cmake/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,77 +5,138 @@
# See LICENSE.TXT
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

# check if all lines match in a file
# lines in a match file can contain regex inside of double curly braces {{}}
# Check if all input file content matches match file content.
# Lines in a match file can contain regex inside of double curly braces {{}}.
# Regex patterns are limited to single line.
#
# List of available special tags:
# {{OPT}} - makes content in the same line as the tag optional
# {{IGNORE}} - ignores all content until next match or end of input file
# Special tags are mutually exclusive and are expected to be located at the start of a line.
#

import sys
import re
from enum import Enum


## @brief print the whole content of input and match files
def print_content(input_lines, match_lines):
def print_content(input_lines, match_lines, ignored_lines):
print("--- Input Lines " + "-" * 64)
print("".join(input_lines).strip())
print("--- Match Lines " + "-" * 64)
print("".join(match_lines).strip())
print("--- Ignored Lines " + "-" * 62)
print("".join(ignored_lines).strip())
print("-" * 80)


if len(sys.argv) != 3:
print("Usage: python match.py <input_file> <match_file>")
sys.exit(1)

input_file = sys.argv[1]
match_file = sys.argv[2]

with open(input_file, 'r') as input, open(match_file, 'r') as match:
input_lines = input.readlines()
match_lines = match.readlines()

if len(match_lines) < len(input_lines):
print(f"Match length < input length (input: {len(input_lines)}, match: {len(match_lines)})")
print_content(input_lines, match_lines)
sys.exit(1)

input_idx = 0
opt = "{{OPT}}"
for i, match_line in enumerate(match_lines):
if match_line.startswith(opt):
optional_line = True
match_line = match_line[len(opt):]
else:
optional_line = False

# split into parts at {{ }}
match_parts = re.split(r'\{{(.*?)\}}', match_line.strip())
pattern = ""
for j, part in enumerate(match_parts):
if j % 2 == 0:
pattern += re.escape(part)
else:
pattern += part
def print_incorrect_match(match_line, present, expected):
print("Line " + str(match_line) + " does not match")
print("is: " + present)
print("expected: " + expected)

# empty input file or end of input file, from now on match file must be optional
if not input_lines:
if optional_line is True:
continue
else:
print("End of input file or empty file.")
print("expected: " + match_line.strip())
sys.exit(1)

input_line = input_lines[input_idx].strip()
if not re.fullmatch(pattern, input_line):
if optional_line is True:
continue
else:
print("Line " + str(i+1) + " does not match")
print("is: " + input_line)
print("expected: " + match_line.strip())
print_content(input_lines, match_lines)
## @brief pattern matching script status values
class Status(Enum):
INPUT_END = 1
MATCH_END = 2
INPUT_AND_MATCH_END = 3
PROCESSING = 4


## @brief check matching script status
def check_status(input_lines, match_lines):
if not input_lines and not match_lines:
return Status.INPUT_AND_MATCH_END
elif not input_lines:
return Status.INPUT_END
elif not match_lines:
return Status.MATCH_END
return Status.PROCESSING


## @brief pattern matching tags.
## Tags are expected to be at the start of the line.
class Tag(Enum):
OPT = "{{OPT}}" # makes the line optional
IGNORE = "{{IGNORE}}" # ignores all input until next match or end of input file


## @brief main function for the match file processing script
def main():
if len(sys.argv) != 3:
print("Usage: python match.py <input_file> <match_file>")
sys.exit(1)

input_file = sys.argv[1]
match_file = sys.argv[2]

with open(input_file, 'r') as input, open(match_file, 'r') as match:
input_lines = input.readlines()
match_lines = match.readlines()

ignored_lines = []

input_idx = 0
match_idx = 0
tag_in_effect = None
status = Status.PROCESSING
while status == Status.PROCESSING:
status = check_status(input_lines[input_idx:], match_lines[match_idx:])
if status == Status.INPUT_AND_MATCH_END:
sys.exit(0)
elif status == Status.MATCH_END:
# last line of the match file is {{IGNORE}} tag, stop processing
if tag_in_effect == Tag.IGNORE:
sys.exit(0)
else:
print_incorrect_match(match_idx + 1, input_lines[input_idx].strip(), "");
print_content(input_lines, match_lines, ignored_lines)
sys.exit(1)
elif status == Status.INPUT_END:
print_incorrect_match(match_idx + 1, "", match_lines[match_idx].strip());
print_content(input_lines, match_lines, ignored_lines)
sys.exit(1)
else:
if (input_idx == len(input_lines) - 1):
input_lines = []
else:
input_idx += 1
input_line = input_lines[input_idx].strip()

match_line = match_lines[match_idx]
if match_line.startswith(Tag.OPT.value):
tag_in_effect = Tag.OPT
match_line = match_line[len(Tag.OPT.value):]
elif match_line.startswith(Tag.IGNORE.value):
tag_in_effect = Tag.IGNORE
match_idx += 1
continue

# split into parts at {{ }}
match_parts = re.split(r'\{{(.*?)\}}', match_line.strip())
pattern = ""
for j, part in enumerate(match_parts):
if j % 2 == 0:
pattern += re.escape(part)
else:
pattern += part

if not re.fullmatch(pattern, input_line):
if tag_in_effect == Tag.OPT:
match_idx += 1
tag_in_effect = None
continue
elif tag_in_effect == Tag.IGNORE:
ignored_lines.append(input_line + "\n")
input_idx += 1
continue
else:
print_incorrect_match(match_idx + 1, input_line, match_line.strip())
print_content(input_lines, match_lines, ignored_lines)
sys.exit(1)

input_idx += 1
match_idx += 1
tag_in_effect = None


if __name__ == "__main__":
main()

0 comments on commit eedc362

Please sign in to comment.