added first code for parser extensions and moved some code in speedups around
--HG--
branch : trunk
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 8b82a4d..4204c6a 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -8,14 +8,15 @@
:copyright: 2008 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
+from operator import itemgetter
from jinja2 import nodes
from jinja2.exceptions import TemplateSyntaxError
_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
- 'macro', 'include', 'trans'])
+ 'macro', 'include'])
_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq', 'in'])
-_statement_end_tokens = set(['elif', 'else', 'endblock', 'endfilter',
+statement_end_tokens = set(['elif', 'else', 'endblock', 'endfilter',
'endfor', 'endif', 'endmacro', 'variable_end',
'in', 'recursive', 'endcall', 'block_end'])
@@ -34,12 +35,13 @@
self.filename = filename
self.closed = False
self.stream = environment.lexer.tokenize(source, filename)
+ self.extensions = environment.parser_extensions
def end_statement(self):
"""Make sure that the statement ends properly."""
if self.stream.current.type is 'semicolon':
self.stream.next()
- elif self.stream.current.type not in _statement_end_tokens:
+ elif self.stream.current.type not in statement_end_tokens:
raise TemplateSyntaxError('ambigous end of statement',
self.stream.current.lineno,
self.filename)
@@ -53,6 +55,10 @@
return self.parse_call_block()
elif token_type is 'filter':
return self.parse_filter_block()
+ elif token_type is 'name':
+ ext = self.extensions.get(self.stream.current.value)
+ if ext is not None:
+ return ext(self)
lineno = self.stream.current
expr = self.parse_tuple()
if self.stream.current.type == 'assign':
@@ -75,10 +81,9 @@
return nodes.Assign(target, expr, lineno=lineno)
def parse_statements(self, end_tokens, drop_needle=False):
- """
- Parse multiple statements into a list until one of the end tokens
- is reached. This is used to parse the body of statements as it
- also parses template data if appropriate.
+ """Parse multiple statements into a list until one of the end tokens
+ is reached. This is used to parse the body of statements as it also
+ parses template data if appropriate.
"""
# the first token may be a colon for python compatibility
if self.stream.current.type is 'colon':
@@ -89,7 +94,7 @@
result = self.subparse(end_tokens)
else:
result = []
- while self.stream.current.type not in end_tokens:
+ while not self.stream.current.test_many(end_tokens):
if self.stream.current.type is 'block_end':
self.stream.next()
result.extend(self.subparse(end_tokens))
@@ -227,20 +232,13 @@
def parse_print(self):
node = nodes.Output(lineno=self.stream.expect('print').lineno)
node.nodes = []
- while self.stream.current.type not in _statement_end_tokens:
+ while self.stream.current.type not in statement_end_tokens:
if node.nodes:
self.stream.expect('comma')
node.nodes.append(self.parse_expression())
self.end_statement()
return node
- def parse_trans(self):
- """Parse a translatable section."""
- # lazily imported because we don't want the i18n overhead
- # if it's not used. (Even though the overhead is low)
- from jinja2.i18n import parse_trans
- return parse_trans(self)
-
def parse_expression(self, no_condexpr=False):
"""Parse an expression."""
if no_condexpr:
@@ -442,7 +440,7 @@
while 1:
if args:
self.stream.expect('comma')
- if self.stream.current.type in _statement_end_tokens:
+ if self.stream.current.type in statement_end_tokens:
break
args.append(parse())
if self.stream.current.type is not 'comma':
@@ -662,7 +660,7 @@
elif token.type is 'variable_begin':
self.stream.next()
want_comma = False
- while self.stream.current.type not in _statement_end_tokens:
+ while not self.stream.current.test_many(statement_end_tokens):
if want_comma:
self.stream.expect('comma')
add_data(self.parse_expression())
@@ -672,7 +670,7 @@
flush_data()
self.stream.next()
if end_tokens is not None and \
- self.stream.current.type in end_tokens:
+ self.stream.current.test_many(end_tokens):
return body
while self.stream.current.type is not 'block_end':
body.append(self.parse_statement())
@@ -688,3 +686,20 @@
result = nodes.Template(self.subparse(), lineno=1)
result.set_environment(self.environment)
return result
+
+
+class ParserExtension(tuple):
+ """Instances of this class store parser extensions."""
+ __slots__ = ()
+
+ def __new__(cls, tag, parse_func):
+ return tuple.__new__(cls, (tag, parse_func))
+
+ def __call__(self, parser):
+ return self.parse_func(parser)
+
+ def __repr__(self):
+ return '<%s %r>' % (self.__class__.__name__, self.tag)
+
+ tag = property(itemgetter(0))
+ parse_func = property(itemgetter(1))