From d874fbeaa8e8e44899de840808c4c651fc1b6238 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 27 Feb 2007 20:51:59 +0100 Subject: [PATCH] [svn] improved lexer and template class --HG-- branch : trunk --- jinja/__init__.py | 4 ++++ jinja/lexer.py | 28 +++++++++++++++++++++------- jinja/parser.py | 5 +++-- jinja/template.py | 27 +++++++++++++++++++++++++-- jinja/translators/python.py | 9 +++++++++ test.py | 7 +------ 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/jinja/__init__.py b/jinja/__init__.py index edf3439..6550d76 100644 --- a/jinja/__init__.py +++ b/jinja/__init__.py @@ -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'] diff --git a/jinja/lexer.py b/jinja/lexer.py index 5f2f72b..2d56adb 100644 --- a/jinja/lexer.py +++ b/jinja/lexer.py @@ -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' + - e(environment.comment_start_string) + - ')|(?P' + - e(environment.block_start_string) + - ')|(?P' + - 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' + + # e(environment.comment_start_string) + + # ')|(?P' + + # e(environment.block_start_string) + + # ')|(?P' + + # e(environment.variable_start_string) + + # '))'), ('data', '#bygroup'), '#bygroup'), (c('.+'), 'data', None) ], 'comment_begin': [ diff --git a/jinja/parser.py b/jinja/parser.py index 34add4f..49f0fa2 100644 --- a/jinja/parser.py +++ b/jinja/parser.py @@ -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: diff --git a/jinja/template.py b/jinja/template.py index ad969d3..780caaa 100644 --- a/jinja/template.py +++ b/jinja/template.py @@ -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) diff --git a/jinja/translators/python.py b/jinja/translators/python.py index 278f873..ed312a8 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -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 d535256..eb079f4 100644 --- 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) -- 2.26.2