pytex/PyTeX/format/macros.py

107 lines
3.3 KiB
Python

import re
from typing import List, Union
from .constants import *
from .enums import FormatterProperty, Argument
class MacroReplacement:
def __init__(
self,
replacement: str,
format_type: str = '%',
*args,
**kwargs
):
self.replacement: str = replacement
self.format_type = '%',
self.args = args
self.kwargs = kwargs
def make_format_args(self, formatter, *call_args):
new_args = []
for arg in self.args:
if type(arg) == FormatterProperty:
try:
new_args.append(getattr(formatter, arg.value))
except:
raise NotImplementedError
elif type(arg) == Argument:
try:
new_args.append(call_args[arg.value - 1])
except:
raise NotImplementedError
elif type(arg) == str:
new_args.append(arg)
else:
raise NotImplementedError
new_kwargs = {}
for kw in self.kwargs.keys():
if type(self.kwargs[kw]) == FormatterProperty:
new_kwargs[kw] = getattr(formatter, self.kwargs[kw].value)
elif type(self.kwargs[kw]) == Argument:
new_kwargs[kw] = call_args[self.kwargs[kw].value - 1]
elif type(self.kwargs[kw]) == str:
new_kwargs[kw] = self.kwargs[kw]
else:
raise NotImplementedError
return new_args, new_kwargs
def format(self, formatter, *call_args) -> str:
args, kwargs = self.make_format_args(formatter, *call_args)
if self.format_type == '%':
if self.args:
raise NotImplementedError # Currently, not supported
return self.replacement % kwargs
elif self.format_type == '{':
return self.replacement.format(
*args, **kwargs
)
else:
raise NotImplementedError
class Macro:
def __init__(self):
raise NotImplementedError
def matches(self, line: str) -> bool:
raise NotImplementedError
def apply(self, line: str, formatter) -> Union[str, List[str]]:
raise NotImplementedError
class BasicMacro(Macro):
def __init__(
self,
macroname,
num_args: int,
macro_replacement: MacroReplacement
):
self.macroname = macroname
self.num_args = num_args
self.macro_replacement: MacroReplacement = macro_replacement
self._search_regex = re.compile(r'{keyword}\({arguments}(?<!@)\)'.format(
keyword=FORMATTER_PREFIX + self.macroname,
arguments=','.join(['(.*?)'] * self.num_args)
))
def matches(self, line: str) -> bool:
match = re.search(self._search_regex, line)
if match is None:
return False
else:
return True
def apply(self, line: str, formatter) -> Union[str, List[str]]:
match = re.search(self._search_regex, line)
if match is None:
raise NotImplementedError
replacement = self.macro_replacement.format(
formatter, match.groups()
)
return line.replace(
match.group(),
replacement
)