""" Data structures for the CSS abstract syntax tree. """ from webencodings import ascii_lower from .serializer import _serialize_to, serialize_identifier, serialize_name class Node: """Every node type inherits from this class, which is never instantiated directly. .. attribute:: type Each child class has a :attr:`type` class attribute with a unique string value. This allows checking for the node type with code like: .. code-block:: python if node.type == 'whitespace': instead of the more verbose: .. code-block:: python from tinycss2.ast import WhitespaceToken if isinstance(node, WhitespaceToken): Every node also has these attributes and methods, which are not repeated for brevity: .. attribute:: source_line The line number of the start of the node in the CSS source. Starts at 1. .. attribute:: source_column The column number within :attr:`source_line` of the start of the node in the CSS source. Starts at 1. .. automethod:: serialize """ __slots__ = ['source_line', 'source_column'] def __init__(self, source_line, source_column): self.source_line = source_line self.source_column = source_column if str is bytes: # pragma: no cover def __repr__(self): return self.repr_format.format(self=self).encode('utf8') else: # pragma: no cover def __repr__(self): return self.repr_format.format(self=self) def serialize(self): """Serialize this node to CSS syntax and return a Unicode string.""" chunks = [] self._serialize_to(chunks.append) return ''.join(chunks) def _serialize_to(self, write): """Serialize this node to CSS syntax, writing chunks as Unicode string by calling the provided :obj:`write` callback. """ raise NotImplementedError # pragma: no cover class ParseError(Node): """A syntax error of some sort. May occur anywhere in the tree. Syntax errors are not fatal in the parser to allow for different error handling behaviors. For example, an error in a Selector list makes the whole rule invalid, but an error in a Media Query list only replaces one comma-separated query with ``not all``. .. autoattribute:: type .. attribute:: kind Machine-readable string indicating the type of error. Example: ``'bad-url'``. .. attribute:: message Human-readable explanation of the error, as a string. Could be translated, expanded to include details, etc. """ __slots__ = ['kind', 'message'] type = 'error' repr_format = '<{self.__class__.__name__} {self.kind}>' def __init__(self, line, column, kind, message): Node.__init__(self, line, column) self.kind = kind self.message = message def _serialize_to(self, write): if self.kind == 'bad-string': write('"[bad string]\n') elif self.kind == 'bad-url': write('url([bad url])') elif self.kind in ')]}': write(self.kind) elif self.kind in ('eof-in-string', 'eof-in-url'): pass else: # pragma: no cover raise TypeError('Can not serialize %r' % self) class Comment(Node): """A CSS comment. Comments can be ignored by passing ``skip_comments=True`` to functions such as :func:`~tinycss2.parse_component_value_list`. .. autoattribute:: type .. attribute:: value The content of the comment, between ``/*`` and ``*/``, as a string. """ __slots__ = ['value'] type = 'comment' repr_format = '<{self.__class__.__name__} {self.value}>' def __init__(self, line, column, value): Node.__init__(self, line, column) self.value = value def _serialize_to(self, write): write('/*') write(self.value) write('*/') class WhitespaceToken(Node): """A :diagram:`whitespace-token`. .. autoattribute:: type .. attribute:: value The whitespace sequence, as a string, as in the original CSS source. """ __slots__ = ['value'] type = 'whitespace' repr_format = '<{self.__class__.__name__}>' def __init__(self, line, column, value): Node.__init__(self, line, column) self.value = value def _serialize_to(self, write): write(self.value) class LiteralToken(Node): r"""Token that represents one or more characters as in the CSS source. .. autoattribute:: type .. attribute:: value A string of one to four characters. Instances compare equal to their :attr:`value`, so that these are equivalent: .. code-block:: python if node == ';': if node.type == 'literal' and node.value == ';': This regroups what `the specification`_ defines as separate token types: .. _the specification: https://drafts.csswg.org/css-syntax-3/ * ** ``:`` * ** ``;`` * ** ``,`` * ** ``-->`` * ** ``