anchor.diff:        astNode.isSynthetic ? '' : astNode.sourceSpan.start.toString();
   }
   
  -class ParseContext {
  +class _TemplateContext {
  +  final Parser parser;
  +  final ElementSchemaRegistry schemaRegistry;
     final List<CompileDirectiveMetadata> directives;
  +
  +  _TemplateContext({this.parser, this.schemaRegistry, this.directives});
  +}
  +
  +class _ParseContext {
  +  final _TemplateContext templateContext;
     final String elementName;
     final List<ng.DirectiveAst> boundDirectives;
   
  -  ParseContext({this.directives, this.elementName, this.boundDirectives});
  -
  -  factory ParseContext.forElement(ast.ElementAst element, ParseContext parent) {
  +  _ParseContext._(this.templateContext, this.elementName, this.boundDirectives);
  +
  +  _ParseContext.forRoot(this.templateContext)
  +      : elementName = '',
  +        boundDirectives = const [];
  +
  +  factory _ParseContext.forElement(
  +      ast.ElementAst element, _TemplateContext templateContext) {
       var boundDirectives = _toAst(
  -        _matchElementDirectives(parent.directives, element),
  +        _matchElementDirectives(templateContext.directives, element),
           element.sourceSpan);
  -    return new ParseContext(
  -        directives: parent.directives,
  -        elementName: element.name,
  -        boundDirectives: boundDirectives);
  -  }
  -
  -  factory ParseContext.forTemplate(
  -      ast.EmbeddedTemplateAst template, ParseContext parent) {
  +    return new _ParseContext._(templateContext, element.name, boundDirectives);
  +  }
  +
  +  factory _ParseContext.forTemplate(
  +      ast.EmbeddedTemplateAst template, _TemplateContext templateContext) {
       var boundDirectives = _toAst(
  -        _matchTemplateDirectives(parent.directives, template),
  +        _matchTemplateDirectives(templateContext.directives, template),
           template.sourceSpan);
  -    return new ParseContext(
  -        directives: parent.directives,
  -        elementName: TEMPLATE_ELEMENT,
  -        boundDirectives: boundDirectives);
  +    return new _ParseContext._(
  +        templateContext, TEMPLATE_ELEMENT, boundDirectives);
     }
   
     static List<ng.DirectiveAst> _toAst(
  
positive.code:         parseExpressions: false);
      // TODO(alorenzen): Remove once all tests are passing.
      parsedAst.forEach(print);
      final filter = new ElementFilter();
      final filteredAst = filter.visitAll(parsedAst);
      final visitor = new Visitor(parser, schemaRegistry);
      final context = new ParseContext(directives: directives);
      return filteredAst
          .map((templateAst) => templateAst.accept(visitor, context))
          .toList();
    }
  }
  
  class Visitor implements ast.TemplateAstVisitor<ng.TemplateAst, ParseContext> {
    final Parser parser;
    final ElementSchemaRegistry schemaRegistry;
  
    /// A count of how many <ng-content> elements have been seen so far.
    ///
    /// This is necessary so that we can assign a unique index to each one as we
    /// visit it.
    int ngContentIndex = 0;
  
    Visitor(this.parser, this.schemaRegistry);
  
    @override
    ng.TemplateAst visitElement(ast.ElementAst astNode, [ParseContext context]) {
      final elementContext = new ParseContext.forElement(astNode, context);
      return new ng.ElementAst(
          astNode.name,
          _visitAll(astNode.attributes, elementContext),
  
negative.code:   }
  
    @override
    ng.TemplateAst visitLetBinding(ast.LetBindingAst astNode,
            [_ParseContext _]) =>
        new ng.VariableAst(astNode.name, astNode.value, astNode.sourceSpan);
  
    @override
    ng.TemplateAst visitReference(ast.ReferenceAst astNode, [_ParseContext _]) =>
        new ng.ReferenceAst(
            astNode.variable, null /* value */, astNode.sourceSpan);
  
    @override
    ng.TemplateAst visitText(ast.TextAst astNode, [_ParseContext _]) =>
        new ng.TextAst(astNode.value, 0 /* ngContentIndex */, astNode.sourceSpan);
  
    @override
    ng.TemplateAst visitInterpolation(ast.InterpolationAst astNode,
        [_ParseContext context]) {
      var element = context.templateContext.parser
          .parseInterpolation('{{${astNode.value}}}', _location(astNode), []);
      return new ng.BoundTextAst(
          element, 0 /* ngContentIndex */, astNode.sourceSpan);
    }
  
    @override
    ng.TemplateAst visitBanana(ast.BananaAst astNode, [_ParseContext _]) =>
        throw new UnimplementedError('Don\'t know how to handle bananas');
  
    @override
    ng.TemplateAst visitCloseElement(ast.CloseElementAst astNode,
            [_ParseContext _]) =>
        throw new UnimplementedError('Don\'t know how to handle close elements');
  
    @override
    ng.TemplateAst visitComment(ast.CommentAst astNode, [_ParseContext _]) =>
        throw new UnimplementedError('Don\'t know how to handle comments.');
  
    @override
    ng.TemplateAst visitExpression(ast.ExpressionAst astNode,
            [_ParseContext _]) =>
        throw new UnimplementedError('Don\'t know how to handle expressions.');
  
    @override
    ng.TemplateAst visitStar(ast.StarAst astNode, [_ParseContext _]) =>
        throw new UnimplementedError('Don\'t know how to handle stars.');
  
    List<T> _visitAll<T extends ng.TemplateAst>(
        List<ast.TemplateAst> astNodes, _ParseContext context) {
      final results = <T>[];
      for (final astNode in astNodes) {
        results.add(astNode.accept(this, context) as T);
  