def _DoSubstitute(args, context, callback, trace):
    """Variable substitution, i.e. {foo}

  We also implement template formatters here, i.e.  {foo|template bar} as well
  as {.template FOO} for templates that operate on the root of the data dict
  rather than a subtree.
  """
    name, formatters = args
    
    if name is None:
        value = context.Root()  # don't use the cursor
    else:
        try:
            value = context.Lookup(name)
        except TypeError as e:
            raise EvaluationError(
                'Error evaluating %r in context %r: %r' % (name, context, e))
    
    last_index = len(formatters) - 1
    for i, (f, args, formatter_type) in enumerate(formatters):
        try:
            if formatter_type == TEMPLATE_FORMATTER:
                template = f.Resolve(context)
                if i == last_index:
                    # In order to keep less template output in memory, we can just let the
                    # other template write to our callback directly, and then stop.
                    template.execute(value, callback, trace=trace)
                    return  # EARLY RETURN
                else:
                    # We have more formatters to apply, so explicitly construct 'value'
                    tokens = []
                    template.execute(value, tokens.append, trace=trace)
                    value = JoinTokens(tokens)
            
            elif formatter_type == ENHANCED_FUNC:
                value = f(value, context, args)
            
            elif formatter_type == SIMPLE_FUNC:
                value = f(value)
            
            else:
                assert False, 'Invalid formatter type %r' % formatter_type
        
        except (KeyboardInterrupt, EvaluationError):
            # Don't "wrap" recursive EvaluationErrors
            raise
        
        except Exception as e:
            if formatter_type == TEMPLATE_FORMATTER:
                raise  # in this case we want to see the original exception
            raise EvaluationError(
                'Formatting name %r, value %r with formatter %s raised exception: %r '
                '-- see e.original_exc_info' % (name, value, f, e),
                original_exc_info=sys.exc_info())
    
    # TODO: Require a string/unicode instance here?
    if value is None:
        raise EvaluationError('Evaluating %r gave None value' % name)
    callback(value)