code: func Parse(r io.Reader, path string) (*Template, error) {
  	s := NewScanner(r, path)
  	t := &Template{Path: path}
  	for {
  		blk, err := s.Scan()
  		if err == io.EOF {
  			break
  		} else if err != nil {
  			return nil, err
  		}
  
  		switch blk := blk.(type) {
  		case *ComponentStartBlock:
  			if err := parseComponentBlock(s, blk); err != nil {
  				return nil, err
  			}
  		case *ComponentEndBlock:
  			return nil, NewSyntaxError(blk.Pos, "Component end block found without matching start block: %s", shortComponentBlockString(blk))
  		case *AttrStartBlock:
  			return nil, NewSyntaxError(blk.Pos, "Attribute start block found outside of component: %s", shortComponentBlockString(blk))
  		case *AttrEndBlock:
  			return nil, NewSyntaxError(blk.Pos, "Attribute end block found outside of component: %s", shortComponentBlockString(blk))
  		}
  
  		t.Blocks = append(t.Blocks, blk)
  	}
  	t.Blocks = normalizeBlocks(t.Blocks)
  	return t, nil
  }
docs: // Parse parses an Ego template from a reader.
  // The path specifies the path name used in the compiled template's pragmas.