[svn] improved lexer and template class
authorArmin Ronacher <armin.ronacher@active-4.com>
Tue, 27 Feb 2007 19:51:59 +0000 (20:51 +0100)
committerArmin Ronacher <armin.ronacher@active-4.com>
Tue, 27 Feb 2007 19:51:59 +0000 (20:51 +0100)
--HG--
branch : trunk

jinja/__init__.py
jinja/lexer.py
jinja/parser.py
jinja/template.py
jinja/translators/python.py
test.py

index edf3439a94929b7f6b53fc1b69781a2b5ca9277c..6550d76a7e70e6e811fde083e7aa4a85f303e40e 100644 (file)
@@ -6,3 +6,7 @@
     :copyright: 2006 by Armin Ronacher.
     :license: BSD, see LICENSE for more details.
 """
+from jinja.environment import Environment
+from jinja.template import Template
+
+__all__ = ['Environment', 'Template']
index 5f2f72b49b4cc1618ffb13d5eb090081af945f7c..2d56adbec9bf4fc1421e9a60624acbbc793e1930 100644 (file)
@@ -64,16 +64,30 @@ class Lexer(object):
             (string_re, 'string', None)
         ]
 
+        # assamble the root lexing rule. because "|" is ungreedy
+        # we have to sort by length so that the lexer continues working
+        # as expected when we have parsing rules like <% for block and
+        # <%= for variables. (if someone wants asp like syntax)
+        root_tag_rules = [
+            ('comment',     environment.comment_start_string),
+            ('block',       environment.block_start_string),
+            ('variable',    environment.variable_start_string)
+        ]
+        root_tag_rules.sort(lambda a, b: cmp(len(b[1]), len(a[1])))
+
         # global parsing rules
         self.rules = {
             'root': [
-                (c('(.*?)(?:(?P<comment_begin>' +
-                    e(environment.comment_start_string) +
-                    ')|(?P<block_begin>' +
-                    e(environment.block_start_string) +
-                    ')|(?P<variable_begin>' +
-                    e(environment.variable_start_string) +
-                   '))'), ('data', '#bygroup'), '#bygroup'),
+                (c('(.*?)(?:%s)' % '|'.join([
+                    '(?P<%s_begin>%s)' % (n, e(r)) for n, r in root_tag_rules
+                ])), ('data', '#bygroup'), '#bygroup'),
+                #(c('(.*?)(?:(?P<comment_begin>' +
+                #    e(environment.comment_start_string) +
+                #    ')|(?P<block_begin>' +
+                #    e(environment.block_start_string) +
+                #    ')|(?P<variable_begin>' +
+                #    e(environment.variable_start_string) +
+                #   '))'), ('data', '#bygroup'), '#bygroup'),
                 (c('.+'), 'data', None)
             ],
             'comment_begin': [
index 34add4f5361ca5add023713e17ff63fdeb874d95..49f0fa221019882a8a7c1a7ff24206f101aa26a4 100644 (file)
@@ -230,7 +230,8 @@ class Parser(object):
 
                 # first token *must* be a name token
                 if token != 'name':
-                    raise TemplateSyntaxError('unexpected %r token' % token, lineno)
+                    raise TemplateSyntaxError('unexpected %r token (%r)' % (
+                                              token, data), lineno)
 
                 # if a test function is passed to subparse we check if we
                 # reached the end of such a requested block.
@@ -256,7 +257,7 @@ class Parser(object):
 
             # so this should be unreachable code
             else:
-                raise AssertionError('unexpected token %r(%r)' % (token, data))
+                raise AssertionError('unexpected token %r (%r)' % (token, data))
 
         # still here and a test function is provided? raise and error
         if test is not None:
index ad969d315c230b17841cc84497e2a98f3eccdb91..780caaa9d168e6b4ec691ba7b401dc08602a0f11 100644 (file)
@@ -9,7 +9,18 @@
     :license: BSD, see LICENSE for more details.
 
 """
+from jinja.nodes import Node
 from jinja.datastructure import Context
+from jinja.translators.python import parse_and_translate, translate
+
+
+def evaluate_source(source):
+    """
+    Evaluate a sourcecode and return the generate function.
+    """
+    ns = {}
+    exec source in ns
+    return ns['generate']
 
 
 class Template(object):
@@ -17,11 +28,23 @@ class Template(object):
     Represents a finished template.
     """
 
-    def __init__(self, environment, generate_func):
+    def __init__(self, environment, source):
+        if isinstance(source, basestring):
+            self.source = parse_and_translate(environment, source)
+        elif isinstance(source, Node):
+            self.source = translate(environment, source)
+        else:
+            raise TypeError('unsupported source type %r' %
+                            source.__class__.__name__)
         self.environment = environment
-        self.generate_func = generate_func
+        self.generate_func = None
 
     def render(self, *args, **kwargs):
+        """
+        Render a template.
+        """
+        if self.generate_func is None:
+            self.generate_func = evaluate_source(self.source)
         result = []
         ctx = Context(self.environment, *args, **kwargs)
         self.generate_func(ctx, result.append)
index 278f873a31bd9339c07bef3861493e287e6c1357..ed312a8865900fef44eeb80b196af8b530eacf71 100644 (file)
@@ -10,6 +10,7 @@
 """
 from compiler import ast
 from jinja import nodes
+from jinja.parser import Parser
 from jinja.exceptions import TemplateSyntaxError
 
 
@@ -549,3 +550,11 @@ def translate(environment, node):
     Do the translation to python.
     """
     return PythonTranslator(environment, node).translate()
+
+
+def parse_and_translate(environment, source, filename=None):
+    """
+    Parse sourcecode and translate it to python
+    """
+    node = Parser(environment, source, filename).parse()
+    return PythonTranslator(environment, node).translate()
diff --git a/test.py b/test.py
index d5352563ec74dfe9855fb834ed3eb5342444ea34..eb079f4236dc6eb83a25f96733c3adf720abc760 100644 (file)
--- a/test.py
+++ b/test.py
@@ -15,9 +15,4 @@ def test_parser(x):
 
 def load_template(x):
     from jinja.template import Template
-    from jinja.parser import Parser
-    from jinja.translators.python import translate
-    code = translate(e, Parser(e, x).parse())
-    ns = {}
-    exec code in ns
-    return Template(e, ns['generate'])
+    return Template(e, x)