code: func (r *Registry) Add(soyfile *ast.SoyFileNode) error {
  	if r.sourceByTemplateName == nil {
  		r.sourceByTemplateName = make(map[string]string)
  	}
  	if r.fileByTemplateName == nil {
  		r.fileByTemplateName = make(map[string]string)
  	}
  	var ns *ast.NamespaceNode
  	for _, node := range soyfile.Body {
  		switch node := node.(type) {
  		case *ast.SoyDocNode:
  			continue
  		case *ast.NamespaceNode:
  			ns = node
  		default:
  			return fmt.Errorf("expected namespace, found %v", node)
  		}
  		break
  	}
  	if ns == nil {
  		return fmt.Errorf("namespace required")
  	}
  
  	r.SoyFiles = append(r.SoyFiles, soyfile)
  	for i := 0; i < len(soyfile.Body); i++ {
  		var tn, ok = soyfile.Body[i].(*ast.TemplateNode)
  		if !ok {
  			continue
  		}
  
  		// Technically every template requires soydoc, but having to add empty
  		// soydoc just to get a template to compile is just stupid.  (There is a
  		// separate data ref check to ensure any variables used are declared as
  		// params, anyway).
  		sdn, ok := soyfile.Body[i-1].(*ast.SoyDocNode)
  		if !ok {
  			sdn = &ast.SoyDocNode{tn.Pos, nil}
  		}
  		r.Templates = append(r.Templates, Template{sdn, tn, ns})
  		r.sourceByTemplateName[tn.Name] = soyfile.Text
  		r.fileByTemplateName[tn.Name] = soyfile.Name
  	}
  	return nil
  }
docs: // Add the given soy file node (and all contained templates) to this registry.