1# # header
2# coding: utf-8
3
4from __future__ import unicode_literals
5
6if False:  # MYPY
7    from typing import Text, Any, Dict, Optional, List  # NOQA
8    from .error import StreamMark  # NOQA
9
10SHOWLINES = True
11
12
13class Token(object):
14    __slots__ = 'start_mark', 'end_mark', '_comment'
15
16    def __init__(self, start_mark, end_mark):
17        # type: (StreamMark, StreamMark) -> None
18        self.start_mark = start_mark
19        self.end_mark = end_mark
20
21    def __repr__(self):
22        # type: () -> Any
23        # attributes = [key for key in self.__slots__ if not key.endswith('_mark') and
24        #               hasattr('self', key)]
25        attributes = [key for key in self.__slots__ if not key.endswith('_mark')]
26        attributes.sort()
27        arguments = ', '.join(['%s=%r' % (key, getattr(self, key)) for key in attributes])
28        if SHOWLINES:
29            try:
30                arguments += ', line: ' + str(self.start_mark.line)
31            except:  # NOQA
32                pass
33        try:
34            arguments += ', comment: ' + str(self._comment)
35        except:  # NOQA
36            pass
37        return '{}({})'.format(self.__class__.__name__, arguments)
38
39    def add_post_comment(self, comment):
40        # type: (Any) -> None
41        if not hasattr(self, '_comment'):
42            self._comment = [None, None]
43        self._comment[0] = comment
44
45    def add_pre_comments(self, comments):
46        # type: (Any) -> None
47        if not hasattr(self, '_comment'):
48            self._comment = [None, None]
49        assert self._comment[1] is None
50        self._comment[1] = comments
51
52    def get_comment(self):
53        # type: () -> Any
54        return getattr(self, '_comment', None)
55
56    @property
57    def comment(self):
58        # type: () -> Any
59        return getattr(self, '_comment', None)
60
61    def move_comment(self, target, empty=False):
62        # type: (Any, bool) -> Any
63        """move a comment from this token to target (normally next token)
64        used to combine e.g. comments before a BlockEntryToken to the
65        ScalarToken that follows it
66        empty is a special for empty values -> comment after key
67        """
68        c = self.comment
69        if c is None:
70            return
71        # don't push beyond last element
72        if isinstance(target, (StreamEndToken, DocumentStartToken)):
73            return
74        delattr(self, '_comment')
75        tc = target.comment
76        if not tc:  # target comment, just insert
77            # special for empty value in key: value issue 25
78            if empty:
79                c = [c[0], c[1], None, None, c[0]]
80            target._comment = c
81            # nprint('mco2:', self, target, target.comment, empty)
82            return self
83        if c[0] and tc[0] or c[1] and tc[1]:
84            raise NotImplementedError('overlap in comment %r %r' % (c, tc))
85        if c[0]:
86            tc[0] = c[0]
87        if c[1]:
88            tc[1] = c[1]
89        return self
90
91    def split_comment(self):
92        # type: () -> Any
93        """ split the post part of a comment, and return it
94        as comment to be added. Delete second part if [None, None]
95         abc:  # this goes to sequence
96           # this goes to first element
97           - first element
98        """
99        comment = self.comment
100        if comment is None or comment[0] is None:
101            return None  # nothing to do
102        ret_val = [comment[0], None]
103        if comment[1] is None:
104            delattr(self, '_comment')
105        return ret_val
106
107
108# class BOMToken(Token):
109#     id = '<byte order mark>'
110
111
112class DirectiveToken(Token):
113    __slots__ = 'name', 'value'
114    id = '<directive>'
115
116    def __init__(self, name, value, start_mark, end_mark):
117        # type: (Any, Any, Any, Any) -> None
118        Token.__init__(self, start_mark, end_mark)
119        self.name = name
120        self.value = value
121
122
123class DocumentStartToken(Token):
124    __slots__ = ()
125    id = '<document start>'
126
127
128class DocumentEndToken(Token):
129    __slots__ = ()
130    id = '<document end>'
131
132
133class StreamStartToken(Token):
134    __slots__ = ('encoding',)
135    id = '<stream start>'
136
137    def __init__(self, start_mark=None, end_mark=None, encoding=None):
138        # type: (Any, Any, Any) -> None
139        Token.__init__(self, start_mark, end_mark)
140        self.encoding = encoding
141
142
143class StreamEndToken(Token):
144    __slots__ = ()
145    id = '<stream end>'
146
147
148class BlockSequenceStartToken(Token):
149    __slots__ = ()
150    id = '<block sequence start>'
151
152
153class BlockMappingStartToken(Token):
154    __slots__ = ()
155    id = '<block mapping start>'
156
157
158class BlockEndToken(Token):
159    __slots__ = ()
160    id = '<block end>'
161
162
163class FlowSequenceStartToken(Token):
164    __slots__ = ()
165    id = '['
166
167
168class FlowMappingStartToken(Token):
169    __slots__ = ()
170    id = '{'
171
172
173class FlowSequenceEndToken(Token):
174    __slots__ = ()
175    id = ']'
176
177
178class FlowMappingEndToken(Token):
179    __slots__ = ()
180    id = '}'
181
182
183class KeyToken(Token):
184    __slots__ = ()
185    id = '?'
186
187    # def x__repr__(self):
188    #     return 'KeyToken({})'.format(
189    #         self.start_mark.buffer[self.start_mark.index:].split(None, 1)[0])
190
191
192class ValueToken(Token):
193    __slots__ = ()
194    id = ':'
195
196
197class BlockEntryToken(Token):
198    __slots__ = ()
199    id = '-'
200
201
202class FlowEntryToken(Token):
203    __slots__ = ()
204    id = ','
205
206
207class AliasToken(Token):
208    __slots__ = ('value',)
209    id = '<alias>'
210
211    def __init__(self, value, start_mark, end_mark):
212        # type: (Any, Any, Any) -> None
213        Token.__init__(self, start_mark, end_mark)
214        self.value = value
215
216
217class AnchorToken(Token):
218    __slots__ = ('value',)
219    id = '<anchor>'
220
221    def __init__(self, value, start_mark, end_mark):
222        # type: (Any, Any, Any) -> None
223        Token.__init__(self, start_mark, end_mark)
224        self.value = value
225
226
227class TagToken(Token):
228    __slots__ = ('value',)
229    id = '<tag>'
230
231    def __init__(self, value, start_mark, end_mark):
232        # type: (Any, Any, Any) -> None
233        Token.__init__(self, start_mark, end_mark)
234        self.value = value
235
236
237class ScalarToken(Token):
238    __slots__ = 'value', 'plain', 'style'
239    id = '<scalar>'
240
241    def __init__(self, value, plain, start_mark, end_mark, style=None):
242        # type: (Any, Any, Any, Any, Any) -> None
243        Token.__init__(self, start_mark, end_mark)
244        self.value = value
245        self.plain = plain
246        self.style = style
247
248
249class CommentToken(Token):
250    __slots__ = 'value', 'pre_done'
251    id = '<comment>'
252
253    def __init__(self, value, start_mark, end_mark):
254        # type: (Any, Any, Any) -> None
255        Token.__init__(self, start_mark, end_mark)
256        self.value = value
257
258    def reset(self):
259        # type: () -> None
260        if hasattr(self, 'pre_done'):
261            delattr(self, 'pre_done')
262
263    def __repr__(self):
264        # type: () -> Any
265        v = '{!r}'.format(self.value)
266        if SHOWLINES:
267            try:
268                v += ', line: ' + str(self.start_mark.line)
269                v += ', col: ' + str(self.start_mark.column)
270            except:  # NOQA
271                pass
272        return 'CommentToken({})'.format(v)
273
274    def __eq__(self, other):
275        # type: (Any) -> bool
276        if self.start_mark != other.start_mark:
277            return False
278        if self.end_mark != other.end_mark:
279            return False
280        if self.value != other.value:
281            return False
282        return True
283
284    def __ne__(self, other):
285        # type: (Any) -> bool
286        return not self.__eq__(other)
287