import sys
from pathlib import Path
from typing import Iterator
from lark import Lark, Token, exceptions
from lark.indenter import Indenter
with open("grug_grammar.lark") as f:
grammar: str = f.read()
class TreeIndenter(Indenter):
NL_type = "_NL" OPEN_PAREN_types = [] CLOSE_PAREN_types = [] INDENT_type = "_INDENT" DEDENT_type = "_DEDENT" tab_len = 4
def handle_NL(self, token: Token) -> Iterator[Token]:
indent = len(token.rsplit("\n", 1)[1])
if indent % self.tab_len != 0:
raise IndentationError(
f"Invalid indent of {indent} spaces at line {token.line}, must be multiple of {self.tab_len}"
)
yield from super().handle_NL(token)
parser: Lark = Lark(grammar, start="start", parser="lalr", postlex=TreeIndenter())
def check_dir(path: Path) -> None:
for subdir in sorted(
[d for d in path.iterdir() if d.is_dir()], key=lambda d: d.name
):
for file in sorted(subdir.glob("*.grug"), key=lambda f: f.name):
print(f"Parsing {file}...")
try:
parser.parse(file.read_text()) except exceptions.LarkError as e:
print(f"❌ Grammar error in test: {file}")
print(e)
sys.exit(1)
root: Path = Path("tests")
check_dir(root / "ok")
check_dir(root / "err_runtime")
print("✅ All grammar checks passed")