@@ -41,6 +41,6 @@ class Comment(Node): | |||||
"""The hidden text contained between ``<!--`` and ``-->``.""" | """The hidden text contained between ``<!--`` and ``-->``.""" | ||||
return self._contents | return self._contents | ||||
@value.setter | |||||
@contents.setter | |||||
def contents(self, value): | def contents(self, value): | ||||
self._contents = str(value) | self._contents = str(value) |
@@ -126,7 +126,7 @@ class Builder(object): | |||||
self._write(self._handle_token(token)) | self._write(self._handle_token(token)) | ||||
def _handle_entity(self): | def _handle_entity(self): | ||||
"""Handle a case where a HTML entity is at the head of the tokens.""" | |||||
"""Handle a case where an HTML entity is at the head of the tokens.""" | |||||
token = self._tokens.pop() | token = self._tokens.pop() | ||||
if isinstance(token, tokens.HTMLEntityNumeric): | if isinstance(token, tokens.HTMLEntityNumeric): | ||||
token = self._tokens.pop() | token = self._tokens.pop() | ||||
@@ -35,49 +35,53 @@ will cover ``BAR == 0b10`` and ``BAZ == 0b01``). | |||||
Local (stack-specific) contexts: | Local (stack-specific) contexts: | ||||
* :py:const:`TEMPLATE` (``0b00000000111``) | |||||
* :py:const:`TEMPLATE` | |||||
* :py:const:`TEMPLATE_NAME` (``0b00000000001``) | |||||
* :py:const:`TEMPLATE_PARAM_KEY` (``0b00000000010``) | |||||
* :py:const:`TEMPLATE_PARAM_VALUE` (``0b00000000100``) | |||||
* :py:const:`TEMPLATE_NAME` | |||||
* :py:const:`TEMPLATE_PARAM_KEY` | |||||
* :py:const:`TEMPLATE_PARAM_VALUE` | |||||
* :py:const:`ARGUMENT` (``0b00000011000``) | |||||
* :py:const:`ARGUMENT` | |||||
* :py:const:`ARGUMENT_NAME` (``0b00000001000``) | |||||
* :py:const:`ARGUMENT_DEFAULT` (``0b00000010000``) | |||||
* :py:const:`ARGUMENT_NAME` | |||||
* :py:const:`ARGUMENT_DEFAULT` | |||||
* :py:const:`HEADING` (``0b111111000``) | |||||
* :py:const:`HEADING` | |||||
* :py:const:`HEADING_LEVEL_1` (``0b00000100000``) | |||||
* :py:const:`HEADING_LEVEL_2` (``0b00001000000``) | |||||
* :py:const:`HEADING_LEVEL_3` (``0b00010000000``) | |||||
* :py:const:`HEADING_LEVEL_4` (``0b00100000000``) | |||||
* :py:const:`HEADING_LEVEL_5` (``0b01000000000``) | |||||
* :py:const:`HEADING_LEVEL_6` (``0b10000000000``) | |||||
* :py:const:`HEADING_LEVEL_1` | |||||
* :py:const:`HEADING_LEVEL_2` | |||||
* :py:const:`HEADING_LEVEL_3` | |||||
* :py:const:`HEADING_LEVEL_4` | |||||
* :py:const:`HEADING_LEVEL_5` | |||||
* :py:const:`HEADING_LEVEL_6` | |||||
* :py:const:`COMMENT` | |||||
Global contexts: | Global contexts: | ||||
* :py:const:`GL_HEADING` (``0b1``) | |||||
* :py:const:`GL_HEADING` | |||||
""" | """ | ||||
# Local contexts: | # Local contexts: | ||||
TEMPLATE = 0b00000000111 | |||||
TEMPLATE_NAME = 0b00000000001 | |||||
TEMPLATE_PARAM_KEY = 0b00000000010 | |||||
TEMPLATE_PARAM_VALUE = 0b00000000100 | |||||
ARGUMENT = 0b00000011000 | |||||
ARGUMENT_NAME = 0b00000001000 | |||||
ARGUMENT_DEFAULT = 0b00000010000 | |||||
HEADING = 0b11111100000 | |||||
HEADING_LEVEL_1 = 0b00000100000 | |||||
HEADING_LEVEL_2 = 0b00001000000 | |||||
HEADING_LEVEL_3 = 0b00010000000 | |||||
HEADING_LEVEL_4 = 0b00100000000 | |||||
HEADING_LEVEL_5 = 0b01000000000 | |||||
HEADING_LEVEL_6 = 0b10000000000 | |||||
TEMPLATE = 0b000000000111 | |||||
TEMPLATE_NAME = 0b000000000001 | |||||
TEMPLATE_PARAM_KEY = 0b000000000010 | |||||
TEMPLATE_PARAM_VALUE = 0b000000000100 | |||||
ARGUMENT = 0b000000011000 | |||||
ARGUMENT_NAME = 0b000000001000 | |||||
ARGUMENT_DEFAULT = 0b000000010000 | |||||
HEADING = 0b011111100000 | |||||
HEADING_LEVEL_1 = 0b000000100000 | |||||
HEADING_LEVEL_2 = 0b000001000000 | |||||
HEADING_LEVEL_3 = 0b000010000000 | |||||
HEADING_LEVEL_4 = 0b000100000000 | |||||
HEADING_LEVEL_5 = 0b001000000000 | |||||
HEADING_LEVEL_6 = 0b010000000000 | |||||
COMMENT = 0b100000000000 | |||||
# Global contexts: | # Global contexts: | ||||
@@ -41,8 +41,8 @@ class Tokenizer(object): | |||||
START = object() | START = object() | ||||
END = object() | END = object() | ||||
MARKERS = ["{", "}", "[", "]", "<", ">", "|", "=", "&", "#", "*", ";", ":", | MARKERS = ["{", "}", "[", "]", "<", ">", "|", "=", "&", "#", "*", ";", ":", | ||||
"/", "-", "\n", END] | |||||
regex = re.compile(r"([{}\[\]<>|=&#*;:/\-\n])", flags=re.IGNORECASE) | |||||
"/", "-", "!", "\n", END] | |||||
regex = re.compile(r"([{}\[\]<>|=&#*;:/\-!\n])", flags=re.IGNORECASE) | |||||
def __init__(self): | def __init__(self): | ||||
self._text = None | self._text = None | ||||
@@ -327,7 +327,7 @@ class Tokenizer(object): | |||||
return self._pop(), after_level | return self._pop(), after_level | ||||
def _really_parse_entity(self): | def _really_parse_entity(self): | ||||
"""Actually parse a HTML entity and ensure that it is valid.""" | |||||
"""Actually parse an HTML entity and ensure that it is valid.""" | |||||
self._write(tokens.HTMLEntityStart()) | self._write(tokens.HTMLEntityStart()) | ||||
self._head += 1 | self._head += 1 | ||||
@@ -369,7 +369,7 @@ class Tokenizer(object): | |||||
self._write(tokens.HTMLEntityEnd()) | self._write(tokens.HTMLEntityEnd()) | ||||
def _parse_entity(self): | def _parse_entity(self): | ||||
"""Parse a HTML entity at the head of the wikicode string.""" | |||||
"""Parse an HTML entity at the head of the wikicode string.""" | |||||
reset = self._head | reset = self._head | ||||
self._push() | self._push() | ||||
try: | try: | ||||
@@ -380,6 +380,21 @@ class Tokenizer(object): | |||||
else: | else: | ||||
self._write_all(self._pop()) | self._write_all(self._pop()) | ||||
def _parse_comment(self): | |||||
"""Parse an HTML comment at the head of the wikicode string.""" | |||||
self._head += 4 | |||||
reset = self._head - 1 | |||||
try: | |||||
comment = self._parse(contexts.COMMENT) | |||||
except BadRoute: | |||||
self._head = reset | |||||
self._write_text("<!--") | |||||
else: | |||||
self._write(tokens.CommentStart()) | |||||
self._write_all(comment) | |||||
self._write(tokens.CommentEnd()) | |||||
self._head += 2 | |||||
def _parse(self, context=0): | def _parse(self, context=0): | ||||
"""Parse the wikicode string, using *context* for when to stop.""" | """Parse the wikicode string, using *context* for when to stop.""" | ||||
self._push(context) | self._push(context) | ||||
@@ -390,12 +405,18 @@ class Tokenizer(object): | |||||
self._head += 1 | self._head += 1 | ||||
continue | continue | ||||
if this is self.END: | if this is self.END: | ||||
fail = contexts.TEMPLATE | contexts.ARGUMENT | contexts.HEADING | |||||
fail = (contexts.TEMPLATE | contexts.ARGUMENT | | |||||
contexts.HEADING | contexts.COMMENT) | |||||
if self._context & fail: | if self._context & fail: | ||||
self._fail_route() | self._fail_route() | ||||
return self._pop() | return self._pop() | ||||
next = self._read(1) | next = self._read(1) | ||||
if this == next == "{": | |||||
if self._context & contexts.COMMENT: | |||||
if this == next == "-" and self._read(2) == ">": | |||||
return self._pop() | |||||
else: | |||||
self._write_text(this) | |||||
elif this == next == "{": | |||||
self._parse_template_or_argument() | self._parse_template_or_argument() | ||||
elif this == "|" and self._context & contexts.TEMPLATE: | elif this == "|" and self._context & contexts.TEMPLATE: | ||||
self._handle_template_param() | self._handle_template_param() | ||||
@@ -421,6 +442,11 @@ class Tokenizer(object): | |||||
self._fail_route() | self._fail_route() | ||||
elif this == "&": | elif this == "&": | ||||
self._parse_entity() | self._parse_entity() | ||||
elif this == "<" and next == "!": | |||||
if self._read(2) == self._read(3) == "-": | |||||
self._parse_comment() | |||||
else: | |||||
self._write_text(this) | |||||
else: | else: | ||||
self._write_text(this) | self._write_text(this) | ||||
self._head += 1 | self._head += 1 | ||||