improved debugging for syntax errors

--HG--
branch : trunk
diff --git a/jinja2/datastructure.py b/jinja2/datastructure.py
index 9dab02b..51ffc93 100644
--- a/jinja2/datastructure.py
+++ b/jinja2/datastructure.py
@@ -29,7 +29,9 @@
             return self.type
         elif self.type in reverse_operators:
             return reverse_operators[self.type]
-        return '%s:%s' % (self.type, self.value)
+        elif self.type is 'name':
+            return self.value
+        return self.type
 
     def test(self, expr):
         """Test a token against a token expression.  This can either be a
@@ -147,8 +149,15 @@
     def expect(self, expr):
         """Expect a given token type and return it"""
         if not self.current.test(expr):
+            if ':' in expr:
+                expr = expr.split(':')[1]
+            if self.current.type is 'eof':
+                raise TemplateSyntaxError('unexpected end of template, '
+                                          'expected %r.' % expr,
+                                          self.current.lineno,
+                                          self.filename)
             raise TemplateSyntaxError("expected token %r, got %r" %
-                                      (expr, self.current),
+                                      (expr, str(self.current)),
                                       self.current.lineno,
                                       self.filename)
         try:
diff --git a/jinja2/debug.py b/jinja2/debug.py
index 622f2b3..a9b4439 100644
--- a/jinja2/debug.py
+++ b/jinja2/debug.py
@@ -33,6 +33,24 @@
     return exc_info[:2] + (result_tb or initial_tb,)
 
 
+def translate_syntax_error(error):
+    """When passed a syntax error it will generate a new traceback with
+    more debugging information.
+    """
+    filename = error.filename
+    if filename is None:
+        filename = '<template>'
+    elif isinstance(filename, unicode):
+        filename = filename.encode('utf-8')
+    code = compile('\n' * (error.lineno - 1) + 'raise __jinja_exception__',
+                   filename, 'exec')
+    try:
+        exec code in {'__jinja_exception__': error}
+    except:
+        exc_info = sys.exc_info()
+        return exc_info[:2] + (exc_info[2].tb_next,)
+
+
 def fake_exc_info(exc_info, filename, lineno, tb_back=None):
     """Helper for `translate_exception`."""
     exc_type, exc_value, tb = exc_info
diff --git a/jinja2/environment.py b/jinja2/environment.py
index 8b959e5..2c370c6 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -15,7 +15,8 @@
 from jinja2.optimizer import optimize
 from jinja2.compiler import generate
 from jinja2.runtime import Undefined, Context, concat
-from jinja2.debug import translate_exception
+from jinja2.debug import translate_exception, translate_syntax_error
+from jinja2.exceptions import TemplateSyntaxError
 from jinja2.utils import import_string, LRUCache, Markup, missing
 
 
@@ -271,13 +272,17 @@
             except (TypeError, LookupError):
                 return self.undefined(obj=obj, name=argument)
 
-    def parse(self, source, name=None):
+    def parse(self, source, filename=None):
         """Parse the sourcecode and return the abstract syntax tree.  This
         tree of nodes is used by the compiler to convert the template into
         executable source- or bytecode.  This is useful for debugging or to
         extract information from templates.
         """
-        return Parser(self, source, name).parse()
+        try:
+            return Parser(self, source, filename).parse()
+        except TemplateSyntaxError, e:
+            exc_type, exc_value, tb = translate_syntax_error(e)
+            raise exc_type, exc_value, tb
 
     def lex(self, source, name=None):
         """Lex the given sourcecode and return a generator that yields
@@ -303,7 +308,7 @@
         mainly used internally.
         """
         if isinstance(source, basestring):
-            source = self.parse(source, name)
+            source = self.parse(source, filename)
         if self.optimized:
             node = optimize(source, self, globals or {})
         source = generate(node, self, name, filename)
diff --git a/jinja2/exceptions.py b/jinja2/exceptions.py
index b0853c4..e5b156b 100644
--- a/jinja2/exceptions.py
+++ b/jinja2/exceptions.py
@@ -29,11 +29,11 @@
 class TemplateSyntaxError(TemplateError):
     """Raised to tell the user that there is a problem with the template."""
 
-    def __init__(self, message, lineno, name):
+    def __init__(self, message, lineno, filename):
         TemplateError.__init__(self, '%s (line %s)' % (message, lineno))
         self.message = message
         self.lineno = lineno
-        self.name = name
+        self.filename = filename
 
 
 class TemplateAssertionError(TemplateSyntaxError):