cpython/Tools/clinic/libclinic/language.py

104 lines
3.1 KiB
Python

from __future__ import annotations
import abc
import typing
from collections.abc import (
Iterable,
)
import libclinic
from libclinic import fail
from libclinic.function import (
Module, Class, Function)
if typing.TYPE_CHECKING:
from clinic import Clinic
class Language(metaclass=abc.ABCMeta):
start_line = ""
body_prefix = ""
stop_line = ""
checksum_line = ""
def __init__(self, filename: str) -> None:
self.filename = filename
@abc.abstractmethod
def render(
self,
clinic: Clinic,
signatures: Iterable[Module | Class | Function]
) -> str:
...
def parse_line(self, line: str) -> None:
...
def validate(self) -> None:
def assert_only_one(
attr: str,
*additional_fields: str
) -> None:
"""
Ensures that the string found at getattr(self, attr)
contains exactly one formatter replacement string for
each valid field. The list of valid fields is
['dsl_name'] extended by additional_fields.
e.g.
self.fmt = "{dsl_name} {a} {b}"
# this passes
self.assert_only_one('fmt', 'a', 'b')
# this fails, the format string has a {b} in it
self.assert_only_one('fmt', 'a')
# this fails, the format string doesn't have a {c} in it
self.assert_only_one('fmt', 'a', 'b', 'c')
# this fails, the format string has two {a}s in it,
# it must contain exactly one
self.fmt2 = '{dsl_name} {a} {a}'
self.assert_only_one('fmt2', 'a')
"""
fields = ['dsl_name']
fields.extend(additional_fields)
line: str = getattr(self, attr)
fcf = libclinic.FormatCounterFormatter()
fcf.format(line)
def local_fail(should_be_there_but_isnt: bool) -> None:
if should_be_there_but_isnt:
fail("{} {} must contain {{{}}} exactly once!".format(
self.__class__.__name__, attr, name))
else:
fail("{} {} must not contain {{{}}}!".format(
self.__class__.__name__, attr, name))
for name, count in fcf.counts.items():
if name in fields:
if count > 1:
local_fail(True)
else:
local_fail(False)
for name in fields:
if fcf.counts.get(name) != 1:
local_fail(True)
assert_only_one('start_line')
assert_only_one('stop_line')
field = "arguments" if "{arguments}" in self.checksum_line else "checksum"
assert_only_one('checksum_line', field)
class PythonLanguage(Language):
language = 'Python'
start_line = "#/*[{dsl_name} input]"
body_prefix = "#"
stop_line = "#[{dsl_name} start generated code]*/"
checksum_line = "#/*[{dsl_name} end generated code: {arguments}]*/"