• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import annotations
2import contextlib
3import functools
4import io
5from types import NoneType
6from typing import Any, Protocol, TYPE_CHECKING
7
8from libclinic import unspecified
9from libclinic.block_parser import Block
10from libclinic.converter import CConverter, converters
11from libclinic.converters import buffer, robuffer, rwbuffer
12from libclinic.return_converters import CReturnConverter, return_converters
13if TYPE_CHECKING:
14    from libclinic.app import Clinic
15
16
17class Parser(Protocol):
18    def __init__(self, clinic: Clinic) -> None: ...
19    def parse(self, block: Block) -> None: ...
20
21
22@functools.cache
23def _create_parser_base_namespace() -> dict[str, Any]:
24    ns = dict(
25        CConverter=CConverter,
26        CReturnConverter=CReturnConverter,
27        buffer=buffer,
28        robuffer=robuffer,
29        rwbuffer=rwbuffer,
30        unspecified=unspecified,
31        NoneType=NoneType,
32    )
33    for name, converter in converters.items():
34        ns[f'{name}_converter'] = converter
35    for name, return_converter in return_converters.items():
36        ns[f'{name}_return_converter'] = return_converter
37    return ns
38
39
40def create_parser_namespace() -> dict[str, Any]:
41    base_namespace = _create_parser_base_namespace()
42    return base_namespace.copy()
43
44
45class PythonParser:
46    def __init__(self, clinic: Clinic) -> None:
47        pass
48
49    def parse(self, block: Block) -> None:
50        namespace = create_parser_namespace()
51        with contextlib.redirect_stdout(io.StringIO()) as s:
52            exec(block.input, namespace)
53            block.output = s.getvalue()
54