|
@@ -38,6 +38,10 @@ class Tokenizer(object): |
|
|
self._stacks = [] |
|
|
self._stacks = [] |
|
|
|
|
|
|
|
|
@property |
|
|
@property |
|
|
|
|
|
def _stack(self): |
|
|
|
|
|
return self._stacks[-1][0] |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
def _context(self): |
|
|
def _context(self): |
|
|
return self._stacks[-1][1] |
|
|
return self._stacks[-1][1] |
|
|
|
|
|
|
|
@@ -46,14 +50,15 @@ class Tokenizer(object): |
|
|
self._stacks[-1][1] = value |
|
|
self._stacks[-1][1] = value |
|
|
|
|
|
|
|
|
def _push(self): |
|
|
def _push(self): |
|
|
self._stacks.append([[], 0]) |
|
|
|
|
|
|
|
|
stack, context = [], 0 |
|
|
|
|
|
self._stacks.append([stack, context]) |
|
|
|
|
|
|
|
|
def _pop(self): |
|
|
def _pop(self): |
|
|
return self._stacks.pop()[0] |
|
|
return self._stacks.pop()[0] |
|
|
|
|
|
|
|
|
def _write(self, token, stack=None): |
|
|
def _write(self, token, stack=None): |
|
|
if stack is None: |
|
|
if stack is None: |
|
|
stack = self._stacks[-1][0] |
|
|
|
|
|
|
|
|
stack = self._stack |
|
|
if not stack: |
|
|
if not stack: |
|
|
stack.append(token) |
|
|
stack.append(token) |
|
|
return |
|
|
return |
|
@@ -65,7 +70,7 @@ class Tokenizer(object): |
|
|
|
|
|
|
|
|
def _write_all(self, tokenlist, stack=None): |
|
|
def _write_all(self, tokenlist, stack=None): |
|
|
if stack is None: |
|
|
if stack is None: |
|
|
stack = self._stacks[-1][0] |
|
|
|
|
|
|
|
|
stack = self._stack |
|
|
stack.extend(tokenlist) |
|
|
stack.extend(tokenlist) |
|
|
|
|
|
|
|
|
def _read(self, delta=0, wrap=False): |
|
|
def _read(self, delta=0, wrap=False): |
|
@@ -79,7 +84,7 @@ class Tokenizer(object): |
|
|
def _at_head(self, chars): |
|
|
def _at_head(self, chars): |
|
|
return all([self._read(i) == chars[i] for i in xrange(len(chars))]) |
|
|
return all([self._read(i) == chars[i] for i in xrange(len(chars))]) |
|
|
|
|
|
|
|
|
def _verify_context(self): |
|
|
|
|
|
|
|
|
def _verify_context_pre_stop(self): |
|
|
if self._read() is self.END: |
|
|
if self._read() is self.END: |
|
|
if self._context & contexts.TEMPLATE: |
|
|
if self._context & contexts.TEMPLATE: |
|
|
raise BadRoute(self._pop()) |
|
|
raise BadRoute(self._pop()) |
|
@@ -98,6 +103,14 @@ class Tokenizer(object): |
|
|
return True |
|
|
return True |
|
|
return False |
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
def _verify_context_post_stop(self): |
|
|
|
|
|
if self._context & contexts.TEMPLATE_NAME and self._stack: |
|
|
|
|
|
head = self._stack[-1] |
|
|
|
|
|
if isinstance(head, tokens.Text): |
|
|
|
|
|
text, this = head.text, self._read() |
|
|
|
|
|
if text.strip() and text.endswith("\n") and this != "\n": |
|
|
|
|
|
raise BadRoute(self._pop()) |
|
|
|
|
|
|
|
|
def _parse_template(self): |
|
|
def _parse_template(self): |
|
|
reset = self._head |
|
|
reset = self._head |
|
|
self._head += 2 |
|
|
self._head += 2 |
|
@@ -111,26 +124,33 @@ class Tokenizer(object): |
|
|
self._write_all(template) |
|
|
self._write_all(template) |
|
|
self._write(tokens.TemplateClose()) |
|
|
self._write(tokens.TemplateClose()) |
|
|
|
|
|
|
|
|
|
|
|
def _handle_template_param(self): |
|
|
|
|
|
if self._context & contexts.TEMPLATE_NAME: |
|
|
|
|
|
self._context ^= contexts.TEMPLATE_NAME |
|
|
|
|
|
if self._context & contexts.TEMPLATE_PARAM_VALUE: |
|
|
|
|
|
self._context ^= contexts.TEMPLATE_PARAM_VALUE |
|
|
|
|
|
self._context |= contexts.TEMPLATE_PARAM_KEY |
|
|
|
|
|
self._write(tokens.TemplateParamSeparator()) |
|
|
|
|
|
|
|
|
|
|
|
def _handle_template_param_value(self): |
|
|
|
|
|
self._context ^= contexts.TEMPLATE_PARAM_KEY |
|
|
|
|
|
self._context |= contexts.TEMPLATE_PARAM_VALUE |
|
|
|
|
|
self._write(tokens.TemplateParamEquals()) |
|
|
|
|
|
|
|
|
def _parse_until(self, stop, context=0): |
|
|
def _parse_until(self, stop, context=0): |
|
|
self._push() |
|
|
self._push() |
|
|
self._context = context |
|
|
self._context = context |
|
|
while True: |
|
|
while True: |
|
|
self._verify_context() |
|
|
|
|
|
|
|
|
self._verify_context_pre_stop() |
|
|
if self._catch_stop(stop): |
|
|
if self._catch_stop(stop): |
|
|
return self._pop() |
|
|
return self._pop() |
|
|
|
|
|
self._verify_context_post_stop() |
|
|
if self._at_head("{{"): |
|
|
if self._at_head("{{"): |
|
|
self._parse_template() |
|
|
self._parse_template() |
|
|
elif self._at_head("|") and self._context & contexts.TEMPLATE: |
|
|
elif self._at_head("|") and self._context & contexts.TEMPLATE: |
|
|
if self._context & contexts.TEMPLATE_NAME: |
|
|
|
|
|
self._context ^= contexts.TEMPLATE_NAME |
|
|
|
|
|
if self._context & contexts.TEMPLATE_PARAM_VALUE: |
|
|
|
|
|
self._context ^= contexts.TEMPLATE_PARAM_VALUE |
|
|
|
|
|
self._context |= contexts.TEMPLATE_PARAM_KEY |
|
|
|
|
|
self._write(tokens.TemplateParamSeparator()) |
|
|
|
|
|
|
|
|
self._handle_template_param() |
|
|
elif self._at_head("=") and self._context & contexts.TEMPLATE_PARAM_KEY: |
|
|
elif self._at_head("=") and self._context & contexts.TEMPLATE_PARAM_KEY: |
|
|
self._context ^= contexts.TEMPLATE_PARAM_KEY |
|
|
|
|
|
self._context |= contexts.TEMPLATE_PARAM_VALUE |
|
|
|
|
|
self._write(tokens.TemplateParamEquals()) |
|
|
|
|
|
|
|
|
self._handle_template_param_value() |
|
|
else: |
|
|
else: |
|
|
self._write(tokens.Text(text=self._read())) |
|
|
self._write(tokens.Text(text=self._read())) |
|
|
self._head += 1 |
|
|
self._head += 1 |
|
|