=== modified file 'django/contrib/admin/templatetags/admin_modify.py'
--- django/contrib/admin/templatetags/admin_modify.py	2007-05-31 20:51:21 +0000
+++ django/contrib/admin/templatetags/admin_modify.py	2007-05-31 21:06:36 +0000
@@ -71,7 +71,7 @@
     default = None
 
     def __init__(self, bound_field_var):
-        self.bound_field_var = bound_field_var
+        self.bound_field_var = template.Variable(bound_field_var)
 
     def get_nodelist(cls, klass):
         if klass not in cls.nodelists:
@@ -95,7 +95,7 @@
     get_nodelist = classmethod(get_nodelist)
 
     def render(self, context):
-        bound_field = template.resolve_variable(self.bound_field_var, context)
+        bound_field = self.bound_field_var.resolve(context)
 
         context.push()
         context['bound_field'] = bound_field
@@ -155,10 +155,10 @@
 
 class EditInlineNode(template.Node):
     def __init__(self, rel_var):
-        self.rel_var = rel_var
+        self.rel_var = template.Variable(rel_var)
 
     def render(self, context):
-        relation = template.resolve_variable(self.rel_var, context)
+        relation = self.rel_var.resolve(context)
         context.push()
         if relation.field.rel.edit_inline == models.TABULAR:
             bound_related_object_class = TabularBoundRelatedObject

=== modified file 'django/contrib/comments/templatetags/comments.py'
--- django/contrib/comments/templatetags/comments.py	2007-05-31 20:51:21 +0000
+++ django/contrib/comments/templatetags/comments.py	2007-05-31 21:06:36 +0000
@@ -18,6 +18,8 @@
         ratings_optional=False, ratings_required=False, rating_options='',
         is_public=True):
         self.content_type = content_type
+        if obj_id_lookup is not None:
+            obj_id_lookup = template.Variable
         self.obj_id_lookup_var, self.obj_id, self.free = obj_id_lookup_var, obj_id, free
         self.photos_optional, self.photos_required = photos_optional, photos_required
         self.ratings_optional, self.ratings_required = ratings_optional, ratings_required
@@ -31,7 +33,7 @@
         context.push()
         if self.obj_id_lookup_var is not None:
             try:
-                self.obj_id = template.resolve_variable(self.obj_id_lookup_var, context)
+                self.obj_id = self.obj_id_lookup_var.resolve(context)
             except template.VariableDoesNotExist:
                 return ''
             # Validate that this object ID is valid for this content-type.
@@ -74,6 +76,8 @@
 class CommentCountNode(template.Node):
     def __init__(self, package, module, context_var_name, obj_id, var_name, free):
         self.package, self.module = package, module
+        if context_var_name is not None:
+            context_var_name = template.Variable(context_var_name)
         self.context_var_name, self.obj_id = context_var_name, obj_id
         self.var_name, self.free = var_name, free
 
@@ -81,7 +85,7 @@
         from django.conf import settings
         manager = self.free and FreeComment.objects or Comment.objects
         if self.context_var_name is not None:
-            self.obj_id = template.resolve_variable(self.context_var_name, context)
+            self.obj_id = self.context_var_name.resolve(context)
         comment_count = manager.filter(object_id__exact=self.obj_id,
             content_type__app_label__exact=self.package,
             content_type__model__exact=self.module, site__id__exact=settings.SITE_ID).count()
@@ -91,6 +95,8 @@
 class CommentListNode(template.Node):
     def __init__(self, package, module, context_var_name, obj_id, var_name, free, ordering, extra_kwargs=None):
         self.package, self.module = package, module
+        if context_var_name is not None:
+            context_var_name = template.Variable(context_var_name)
         self.context_var_name, self.obj_id = context_var_name, obj_id
         self.var_name, self.free = var_name, free
         self.ordering = ordering
@@ -101,7 +107,7 @@
         get_list_function = self.free and FreeComment.objects.filter or Comment.objects.get_list_with_karma
         if self.context_var_name is not None:
             try:
-                self.obj_id = template.resolve_variable(self.context_var_name, context)
+                self.obj_id = self.context_var_name.resolve(context)
             except template.VariableDoesNotExist:
                 return ''
         kwargs = {

=== modified file 'django/template/__init__.py'
--- django/template/__init__.py	2007-05-31 20:51:24 +0000
+++ django/template/__init__.py	2007-05-31 21:06:37 +0000
@@ -91,8 +91,6 @@
 tag_re = re.compile('(%s.*?%s|%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
                                           re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
                                           re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END)))
-# matches if the string is valid number
-number_re = re.compile(r'[-+]?(\d+|\d*\.\d+)$')
 
 # global dictionary of libraries that have been loaded using get_library
 libraries = {}
@@ -562,18 +560,19 @@
                 elif constant_arg is not None:
                     args.append((False, constant_arg.replace(r'\"', '"')))
                 elif var_arg:
-                    args.append((True, var_arg))
+                    args.append((True, Variable(var_arg)))
                 filter_func = parser.find_filter(filter_name)
                 self.args_check(filter_name,filter_func, args)
                 filters.append( (filter_func,args))
                 upto = match.end()
         if upto != len(token):
             raise TemplateSyntaxError, "Could not parse the remainder: '%s' from '%s'" % (token[upto:], token)
-        self.var, self.filters = var, filters
+        self.filters = filters
+        self.var = Variable(var)
 
     def resolve(self, context, ignore_failures=False):
         try:
-            obj = resolve_variable(self.var, context)
+            obj = self.var.resolve(context)
         except VariableDoesNotExist:
             if ignore_failures:
                 obj = None
@@ -593,7 +592,7 @@
                 if not lookup:
                     arg_vals.append(arg)
                 else:
-                    arg_vals.append(resolve_variable(arg, context))
+                    arg_vals.append(arg.resolve(context))
             obj = func(obj, *arg_vals)
         return obj
 
@@ -652,20 +651,49 @@
 
     (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
     """
-    if number_re.match(path):
-        number_type = '.' in path and float or int
-        current = number_type(path)
-    elif path[0] in ('"', "'") and path[0] == path[-1]:
-        current = path[1:-1]
-    else:
+    return Variable(path).resolve(context)
+
+class LiteralVariable(object):
+
+    def __init__(self, val):
+        self.val = val
+
+    def resolve(self, context):
+        return self.val
+
+    def __str__(self):
+        return self.val
+
+def Variable(val):
+    try:
+        # note we're not catching OverflowError here; point of debate on how best to handle that...
+        current = float(val)
+        if '.' not in val:
+            # downside to this approach is that 1e07 becomes an int; float may be preferable still.
+            current = int(current)
+        elif val[-1] == '.':
+            # 2. is invalid
+            raise ValueError
+        return LiteralVariable(current)
+    except ValueError:
+        pass
+    if val[0] in "\"'" and val[0] == val[-1]:
+        return LiteralVariable(val[1:-1])
+    return ChainedLookupVariable(val)
+    
+class ChainedLookupVariable(object):
+
+    def __init__(self, val):
+        self.lookups = tuple(val.split(VARIABLE_ATTRIBUTE_SEPARATOR))
+    
+    def resolve(self, context):
         current = context
-        bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
-        while bits:
+        for bit in self.lookups:
             try: # dictionary lookup
-                current = current[bits[0]]
+                current = current[bit]
             except (TypeError, AttributeError, KeyError):
                 try: # attribute lookup
-                    current = getattr(current, bits[0])
+                    current = getattr(current, bit)
                     if callable(current):
                         if getattr(current, 'alters_data', False):
                             current = settings.TEMPLATE_STRING_IF_INVALID
@@ -683,20 +711,22 @@
                                     raise
                 except (TypeError, AttributeError):
                     try: # list-index lookup
-                        current = current[int(bits[0])]
+                        current = current[int(bit)]
                     except (IndexError, # list index out of range
                             ValueError, # invalid literal for int()
-                            KeyError,   # current is a dict without `int(bits[0])` key
+                            KeyError,   # current is a dict without `int(bit)` key
                             TypeError,  # unsubscriptable object
                             ):
-                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bits[0], current)) # missing attribute
+                        raise VariableDoesNotExist("Failed lookup for key [%s] in %r", (bit, current)) # missing attribute
                 except Exception, e:
                     if getattr(e, 'silent_variable_failure', False):
                         current = settings.TEMPLATE_STRING_IF_INVALID
                     else:
                         raise
-            del bits[0]
-    return current
+        return current
+
+    def __str__(self):
+        return VARIABLE_ATTRIBUTE_SEPARATOR.join(self.lookups)
 
 class Node(object):
     def render(self, context):
@@ -867,11 +897,10 @@
 
         class SimpleNode(Node):
             def __init__(self, vars_to_resolve):
-                self.vars_to_resolve = vars_to_resolve
+                self.vars_to_resolve = map(Variable, vars_to_resolve)
 
             def render(self, context):
-                resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
-                return func(*resolved_vars)
+                return func(*[var.resolve(context) for var in self.vars_to_resolve])
 
         compile_func = curry(generic_tag_compiler, params, defaults, getattr(func, "_decorated_function", func).__name__, SimpleNode)
         compile_func.__doc__ = func.__doc__
@@ -889,10 +918,10 @@
 
             class InclusionNode(Node):
                 def __init__(self, vars_to_resolve):
-                    self.vars_to_resolve = vars_to_resolve
+                    self.vars_to_resolve = map(Variable, vars_to_resolve)
 
                 def render(self, context):
-                    resolved_vars = [resolve_variable(var, context) for var in self.vars_to_resolve]
+                    resolved_vars = [var.resolve(context) for var in self.vars_to_resolve]
                     if takes_context:
                         args = [context] + resolved_vars
                     else:

=== modified file 'django/template/defaulttags.py'
--- django/template/defaulttags.py	2007-05-31 20:51:24 +0000
+++ django/template/defaulttags.py	2007-05-31 21:06:37 +0000
@@ -1,6 +1,6 @@
 "Default tags used by the template system, available to all templates."
 
-from django.template import Node, NodeList, Template, Context, resolve_variable
+from django.template import Node, NodeList, Template, Context, Variable
 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
 from django.template import get_library, Library, InvalidTemplateLibrary
 from django.conf import settings
@@ -48,12 +48,12 @@
 
 class FirstOfNode(Node):
     def __init__(self, vars):
-        self.vars = vars
+        self.vars = map(Variable, vars)
 
     def render(self, context):
         for var in self.vars:
             try:
-                value = resolve_variable(var, context)
+                value = var.resolve(context)
             except VariableDoesNotExist:
                 continue
             if value:
@@ -130,7 +130,7 @@
     def __init__(self, nodelist, *varlist):
         self.nodelist = nodelist
         self._last_seen = None
-        self._varlist = varlist
+        self._varlist = map(Variable, varlist)
 
     def render(self, context):
         if 'forloop' in context and context['forloop']['first']:
@@ -139,7 +139,7 @@
             if self._varlist:
                 # Consider multiple parameters.
                 # This automatically behaves like a OR evaluation of the multiple variables.
-                compare_to = [resolve_variable(var, context) for var in self._varlist]
+                compare_to = [var.resolve(context) for var in self._varlist]
             else:
                 compare_to = self.nodelist.render(context)
         except VariableDoesNotExist:
@@ -158,7 +158,7 @@
 
 class IfEqualNode(Node):
     def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
-        self.var1, self.var2 = var1, var2
+        self.var1, self.var2 = Variable(var1), Variable(var2)
         self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
         self.negate = negate
 
@@ -167,11 +167,11 @@
 
     def render(self, context):
         try:
-            val1 = resolve_variable(self.var1, context)
+            val1 = self.var1.resolve(context)
         except VariableDoesNotExist:
             val1 = None
         try:
-            val2 = resolve_variable(self.var2, context)
+            val2 = self.var2.resolve(context)
         except VariableDoesNotExist:
             val2 = None
         if (self.negate and val1 != val2) or (not self.negate and val1 == val2):

=== modified file 'django/template/loader_tags.py'
--- django/template/loader_tags.py	2007-05-31 20:51:24 +0000
+++ django/template/loader_tags.py	2007-05-31 21:06:37 +0000
@@ -1,4 +1,4 @@
-from django.template import TemplateSyntaxError, TemplateDoesNotExist, resolve_variable
+from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
 from django.template import Library, Node
 from django.template.loader import get_template, get_template_from_string, find_template_source
 from django.conf import settings
@@ -99,11 +99,11 @@
 
 class IncludeNode(Node):
     def __init__(self, template_name):
-        self.template_name = template_name
+        self.template_name = Variable(template_name)
 
     def render(self, context):
         try:
-            template_name = resolve_variable(self.template_name, context)
+            template_name = self.template_name.resolve(context)
             t = get_template(template_name)
             return t.render(context)
         except TemplateSyntaxError, e:

=== modified file 'django/templatetags/i18n.py'
--- django/templatetags/i18n.py	2007-05-31 20:51:24 +0000
+++ django/templatetags/i18n.py	2007-05-31 21:06:37 +0000
@@ -1,4 +1,4 @@
-from django.template import Node, resolve_variable
+from django.template import Node, Variable
 from django.template import TemplateSyntaxError, TokenParser, Library
 from django.template import TOKEN_TEXT, TOKEN_VAR
 from django.utils import translation
@@ -32,11 +32,11 @@
 
 class TranslateNode(Node):
     def __init__(self, value, noop):
-        self.value = value
+        self.value = Variable(value)
         self.noop = noop
 
     def render(self, context):
-        value = resolve_variable(self.value, context)
+        value = self.value.resolve(context)
         if self.noop:
             return value
         else:

