| from __future__ import annotations
|
|
|
| import re
|
| from typing import TYPE_CHECKING
|
|
|
|
|
| if TYPE_CHECKING:
|
| from collections.abc import Mapping, Sequence
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| class CodeTemplate:
|
| substitution_str = r"(^[^\n\S]*)?\$([^\d\W]\w*|\{,?[^\d\W]\w*\,?})"
|
| substitution = re.compile(substitution_str, re.MULTILINE)
|
|
|
| pattern: str
|
| filename: str
|
|
|
| @staticmethod
|
| def from_file(filename: str) -> CodeTemplate:
|
| with open(filename) as f:
|
| return CodeTemplate(f.read(), filename)
|
|
|
| def __init__(self, pattern: str, filename: str = "") -> None:
|
| self.pattern = pattern
|
| self.filename = filename
|
|
|
| def substitute(
|
| self, env: Mapping[str, object] | None = None, **kwargs: object
|
| ) -> str:
|
| if env is None:
|
| env = {}
|
|
|
| def lookup(v: str) -> object:
|
| assert env is not None
|
| return kwargs[v] if v in kwargs else env[v]
|
|
|
| def indent_lines(indent: str, v: Sequence[object]) -> str:
|
| return "".join(
|
| [indent + l + "\n" for e in v for l in str(e).splitlines()]
|
| ).rstrip()
|
|
|
| def replace(match: re.Match[str]) -> str:
|
| indent = match.group(1)
|
| key = match.group(2)
|
| comma_before = ""
|
| comma_after = ""
|
| if key[0] == "{":
|
| key = key[1:-1]
|
| if key[0] == ",":
|
| comma_before = ", "
|
| key = key[1:]
|
| if key[-1] == ",":
|
| comma_after = ", "
|
| key = key[:-1]
|
| v = lookup(key)
|
| if indent is not None:
|
| if not isinstance(v, list):
|
| v = [v]
|
| return indent_lines(indent, v)
|
| elif isinstance(v, list):
|
| middle = ", ".join([str(x) for x in v])
|
| if len(v) == 0:
|
| return middle
|
| return comma_before + middle + comma_after
|
| else:
|
| return str(v)
|
|
|
| return self.substitution.sub(replace, self.pattern)
|
|
|
|
|
| if __name__ == "__main__":
|
| c = CodeTemplate(
|
| """\
|
| int foo($args) {
|
|
|
| $bar
|
| $bar
|
| $a+$b
|
| }
|
| int commatest(int a${,stuff})
|
| int notest(int a${,empty,})
|
| """
|
| )
|
| print(
|
| c.substitute(
|
| args=["hi", 8],
|
| bar=["what", 7],
|
| a=3,
|
| b=4,
|
| stuff=["things...", "others"],
|
| empty=[],
|
| )
|
| )
|
|
|