File size: 6,216 Bytes
17e971c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Nginx解析器基础类和接口
"""
from abc import abstractmethod, ABC
from typing import List, Optional, Type, TypeVar
from dataclasses import dataclass, field
from enum import Enum


class TokenType(Enum):
    """词法标记类型"""
    EOF = "EOF"
    KEYWORD = "KEYWORD"
    QUOTED_STRING = "QUOTED_STRING"
    SEMICOLON = "SEMICOLON"
    BLOCK_START = "BLOCK_START"
    BLOCK_END = "BLOCK_END"
    COMMENT = "COMMENT"
    LUA_CODE = "LUA_CODE"
    END_OF_LINE = "END_OF_LINE"  # 新增


@dataclass
class Token:
    """词法标记"""
    type: TokenType
    literal: str
    line: int
    column: int


@dataclass
class Style:
    """输出样式配置"""
    space_before_blocks: bool = False
    start_indent: int = 0
    indent: int = 4

    def iterate(self) -> 'Style':
        """创建下一级缩进的样式"""
        return Style(
            space_before_blocks=self.space_before_blocks,
            start_indent=self.start_indent + self.indent,
            indent=self.indent
        )


# 默认样式
INDENTED_STYLE = Style()


class IDirective(ABC):
    """指令接口"""

    @abstractmethod
    def get_name(self) -> str:
        raise NotImplementedError

    @abstractmethod
    def get_parameters(self) -> List[str]:
        raise NotImplementedError

    @abstractmethod
    def get_block(self) -> Optional['IBlock']:
        raise NotImplementedError

    @abstractmethod
    def get_comment(self) -> List[str]:
        raise NotImplementedError

    @abstractmethod
    def set_comment(self, comment: List[str]):
        raise NotImplementedError

    @abstractmethod
    def get_line(self) -> int:
        raise NotImplementedError

    @abstractmethod
    def set_parent(self, parent: Optional['IDirective']):
        raise NotImplementedError

    @abstractmethod
    def get_parent(self) -> Optional['IDirective']:
        raise NotImplementedError

    @abstractmethod
    def get_inline_comment(self) -> List[str]:
        raise NotImplementedError

    @abstractmethod
    def set_inline_comment(self, comment: str):
        raise NotImplementedError


class IBlock(ABC):
    """块接口"""

    @abstractmethod
    def get_directives(self) -> List[IDirective]:
        raise NotImplementedError

    @abstractmethod
    def get_code_block(self) -> str:
        raise NotImplementedError

    @abstractmethod
    def find_directives(self, directive_name: str, include: bool = False, sub_block: bool = False) -> List[IDirective]:
        """查找指定名称的指令
        :param directive_name: 指令名称
        :param include: 是否包含include子块, 前提是解析时有传递parse_include参数,默认为False
        :param sub_block: 是否包含子块, 对与nginx配置文件来说 {} 包裹的就是一个块, 如: http, server, if, location, map 等
        """
        directives = []
        for directive in self.get_directives():
            if include and directive.get_name() == "include" and directive_name != "include":
                if getattr(directive, 'configs', []) and callable(getattr(directive, 'find_directives', None)):
                    directives.extend(getattr(directive, 'find_directives')(directive_name, include, sub_block))

            if directive.get_name() == directive_name:
                directives.append(directive)
            if sub_block and directive.get_block() is not None:
                directives.extend(directive.get_block().find_directives(directive_name))
        return directives

    @abstractmethod
    def set_parent(self, parent: Optional[IDirective]):
        raise NotImplementedError

    @abstractmethod
    def get_parent(self) -> Optional[IDirective]:
        raise NotImplementedError


@dataclass
class Directive(IDirective):
    """指令实现"""
    line: int = 0
    block: Optional['Block'] = None
    name: str = ""
    comment: List[str] = field(default_factory=list)
    inline_comment: List[str] = field(default_factory=list)
    parameters: List[str] = field(default_factory=list)
    _parent: Optional['IDirective'] = field(default=None, repr=False, compare=False)

    def get_name(self) -> str:
        return self.name

    def get_parameters(self) -> List[str]:
        return self.parameters

    def get_block(self) -> Optional['Block']:
        return self.block

    def get_comment(self) -> List[str]:
        return self.comment

    def set_comment(self, comment: List[str]):
        self.comment = comment

    def get_line(self) -> int:
        return self.line

    def set_parent(self, parent: Optional['IDirective']):
        self._parent = parent

    def get_parent(self) -> Optional['IDirective']:
        return self._parent

    def get_inline_comment(self) -> List[str]:
        return self.inline_comment

    def set_inline_comment(self, comment: str):
        self.inline_comment.append(comment)


@dataclass
class Block(IBlock):
    """块实现"""
    directives: List[IDirective] = field(default_factory=list)
    is_lua_block: bool = False
    literal_code: str = ""
    _parent: Optional[IDirective] = field(default=None, repr=False, compare=False)

    def get_directives(self) -> List[IDirective]:
        return self.directives

    def get_code_block(self) -> str:
        return self.literal_code

    def find_directives(self, directive_name: str, include: bool = False, sub_block: bool = False) -> List[IDirective]:
        """查找指定名称的指令"""
        return super().find_directives(directive_name, include, sub_block)

    def set_parent(self, parent: Optional[IDirective]):
        self._parent = parent

    def get_parent(self) -> Optional[IDirective]:
        return self._parent

    def replace_directive(self, old_directive: IDirective, new_directive: IDirective):
        """替换指令"""
        for i, directive in enumerate(self.directives):
            if directive == old_directive:
                self.directives[i] = new_directive
                break


class _Trans(ABC):
    pass


# 定义类型变量
_T = TypeVar('_T')


def trans_(any_dir, cls: Type[_T]) -> Optional[_T]:
    if cls is any_dir.__class__:
        return any_dir
    return None