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