mirror of https://github.com/python/cpython.git
104 lines
3.1 KiB
Python
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 libclinic.app 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}]*/"
|