Skip to content

Commit

Permalink
add support for --dump-input flag (fixes #19)
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonLydike committed Aug 29, 2024
1 parent 55c6af1 commit eb69a01
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 20 deletions.
5 changes: 5 additions & 0 deletions filecheck/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
match.
--match-full-lines : Expect every check line to match the whole line.
--reject-empty-vars : Raise an error when a value captures an empty string.
--dump-intput : Dump the input to stderr annotated with helpful
information depending on the context. Allowed values
are help, always, never, fail. Default is fail.
Only fail and never is currently supported in this
version of filecheck.
ARGUMENTS:
check-file : The file from which the check lines are to be read
Expand Down
48 changes: 30 additions & 18 deletions filecheck/matcher.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import re
import os
import sys
from collections.abc import Sequence
from dataclasses import dataclass, field
from typing import Callable
from typing import Callable, TextIO

from filecheck.compiler import compile_uops
from filecheck.error import CheckError, ParseError, ErrorOnMatch
from filecheck.finput import FInput, InputRange
from filecheck.logging import warn
from filecheck.colors import ERR, FMT
from filecheck.ops import CheckOp, CountOp, Literal, Subst, UOp, RE, Capture
from filecheck.options import Options
from filecheck.options import Options, DumpInputKind
from filecheck.parser import Parser
from filecheck.preprocess import Preprocessor

Expand Down Expand Up @@ -45,6 +46,8 @@ class Matcher:

ctx: Context = field(default_factory=Context)

stderr: TextIO = field(init=False)

@classmethod
def from_opts(cls, opts: Options):
"""
Expand All @@ -56,6 +59,15 @@ def from_opts(cls, opts: Options):

def __post_init__(self):
self.ctx.live_variables.update(self.opts.variables)
if self.opts.dump_input == DumpInputKind.NEVER:
self.stderr = open(os.devnull, "w")
else:
self.stderr = sys.stderr
if self.opts.dump_input in (DumpInputKind.ALWAYS, DumpInputKind.HELP):
warn(
f"Unsupported dump-input flag: {self.opts.dump_input.name.lower()}",
opts=self.opts,
)

def run(self) -> int:
"""
Expand All @@ -67,7 +79,7 @@ def run(self) -> int:
if self.file.content in ("", "\n"):
print(
f"{ERR}filecheck error:{FMT.RESET} '{self.opts.readable_input_file()}' is empty.",
file=sys.stderr,
file=self.stderr,
)
return 1

Expand All @@ -81,16 +93,16 @@ def run(self) -> int:
pref = f"prefixes {', '.join(self.opts.check_prefixes)}"
print(
f"{ERR}filecheck error:{FMT.RESET} No check strings found with {pref}:",
file=sys.stderr,
file=self.stderr,
)
return 2
except ParseError as ex:
print(
f"{self.opts.match_filename}:{ex.line_no}:{ex.offset} {ex.message}",
file=sys.stderr,
file=self.stderr,
)
print(ex.offending_line.rstrip("\n"), file=sys.stderr)
print(" " * (ex.offset - 1) + "^", file=sys.stderr)
print(ex.offending_line.rstrip("\n"), file=self.stderr)
print(" " * (ex.offset - 1) + "^", file=self.stderr)
return 1

function_table: dict[str, Callable[[CheckOp], None]] = {
Expand Down Expand Up @@ -122,40 +134,40 @@ def run(self) -> int:
except CheckError as ex:
print(
f"{self.opts.match_filename}:{ex.op.source_line}: {ERR}error:{FMT.RESET} {ex.message}",
file=sys.stderr,
file=self.stderr,
)
print("Current position at " + self.file.print_line(), file=sys.stderr)
print("Current position at " + self.file.print_line(), file=self.stderr)

if self.file.is_discontigous():
print(
"\nCurrently matching in range (grey is already matched):",
file=sys.stderr,
file=self.stderr,
)
print("".join(self.file.print_current_range()), file=sys.stderr)
print("".join(self.file.print_current_range()), file=self.stderr)

# try to look for a shorter match, and print that if possible
prefix_match = self.find_prefix_match_for(ex.op)
if prefix_match is not None:
print("Possible intended match at:", file=sys.stderr)
print(self.file.print_line(prefix_match.start(0)), file=sys.stderr)
print("Possible intended match at:", file=self.stderr)
print(self.file.print_line(prefix_match.start(0)), file=self.stderr)

return 1
except ErrorOnMatch as ex:
print(
f"{self.opts.match_filename}:{ex.op.source_line}: {ERR}error:{FMT.RESET} {ex.message}",
file=sys.stderr,
file=self.stderr,
)
print("Matching at: ", end="", file=sys.stderr)
print("Matching at: ", end="", file=self.stderr)
print(
self.file.print_line(ex.match.start(0), ex.match.end(0)),
file=sys.stderr,
file=self.stderr,
)
if self.file.is_discontigous():
print(
"\nCurrently matching in range (grey is already matched):",
file=sys.stderr,
file=self.stderr,
)
print("".join(self.file.print_current_range()), file=sys.stderr)
print("".join(self.file.print_current_range()), file=self.stderr)
return 1

return 0
Expand Down
20 changes: 18 additions & 2 deletions filecheck/options.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass, field
from enum import Enum
from enum import Enum, auto
from typing import Iterable
import os

Expand All @@ -8,6 +8,13 @@ class Extension(Enum):
MLIR_REGEX_CLS = "MLIR_REGEX_CLS"


class DumpInputKind(Enum):
HELP = auto()
ALWAYS = auto()
NEVER = auto()
FAIL = auto()


@dataclass
class Options:
match_filename: str
Expand All @@ -19,6 +26,7 @@ class Options:
match_full_lines: bool = False
allow_empty: bool = False
reject_empty_vars: bool = False
dump_input: DumpInputKind = DumpInputKind.FAIL
variables: dict[str, str | int] = field(default_factory=dict)

extensions: set[Extension] = field(default_factory=set)
Expand All @@ -32,7 +40,7 @@ def __post_init__(self):
extensions: set[Extension] = set()
for ext in self.extensions:
if isinstance(ext, str):
if ext in set(e.name for e in Extension):
if ext in set(e.value for e in Extension):
extensions.add(
Extension[ext] # pyright: ignore[reportArgumentType]
)
Expand All @@ -43,6 +51,14 @@ def __post_init__(self):
else:
extensions.add(ext)
self.extensions = extensions
if isinstance(self.dump_input, str):
name: str = self.dump_input.upper()
if name in set(d.name for d in DumpInputKind):
self.dump_input = DumpInputKind[name]
else:
raise RuntimeError(
f'Unknown value supplied for dump-input flag: "{name}"'
)

def readable_input_file(self):
if self.input_file == "-":
Expand Down
12 changes: 12 additions & 0 deletions tests/filecheck/flags/dump-input.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: strip-comments.sh %s | filecheck %s --dump-input never --check-prefix RIGHT | filecheck %s --allow-empty --check-prefix EMPTY
// RUN: strip-comments.sh %s | exfail filecheck %s --dump-input never --check-prefix WRONG | filecheck %s --allow-empty --check-prefix EMPTY
// RUN: strip-comments.sh %s | filecheck %s --dump-input fail --check-prefix RIGHT | filecheck %s --allow-empty --check-prefix EMPTY
// RUN: strip-comments.sh %s | exfail filecheck %s --dump-input fail --check-prefix WRONG | filecheck %s --allow-empty --check-prefix HAS-OUTPUT
// RUN: strip-comments.sh %s | filecheck %s --dump-input help --check-prefix RIGHT 2>&1 | filecheck %s --allow-empty --check-prefix UNKNOWN-FLAG -DFLAG=help
// RUN: strip-comments.sh %s | filecheck %s --dump-input always --check-prefix RIGHT 2>&1 | filecheck %s --allow-empty --check-prefix UNKNOWN-FLAG -DFLAG=always
test
// RIGHT: test
// WRONG: wrong
// EMPTY-NOT: {{.+}}
// HAS-OUTPUT: error: Couldn't match "wrong".
// UNKNOWN-FLAG: Warning: Unsupported dump-input flag: [[FLAG]]

0 comments on commit eb69a01

Please sign in to comment.