...

Source file src/github.com/mailru/easyjson/parser/parser.go

Documentation: github.com/mailru/easyjson/parser

     1  package parser
     2  
     3  import (
     4  	"go/ast"
     5  	"go/parser"
     6  	"go/token"
     7  	"os"
     8  	"strings"
     9  )
    10  
    11  const (
    12  	structComment     = "easyjson:json"
    13  	structSkipComment = "easyjson:skip"
    14  )
    15  
    16  type Parser struct {
    17  	PkgPath     string
    18  	PkgName     string
    19  	StructNames []string
    20  	AllStructs  bool
    21  }
    22  
    23  type visitor struct {
    24  	*Parser
    25  
    26  	name string
    27  }
    28  
    29  func (p *Parser) needType(comments *ast.CommentGroup) (skip, explicit bool) {
    30  	if comments == nil {
    31  		return
    32  	}
    33  
    34  	for _, v := range comments.List {
    35  		comment := v.Text
    36  
    37  		if len(comment) > 2 {
    38  			switch comment[1] {
    39  			case '/':
    40  				// -style comment (no newline at the end)
    41  				comment = comment[2:]
    42  			case '*':
    43  				/*-style comment */
    44  				comment = comment[2 : len(comment)-2]
    45  			}
    46  		}
    47  
    48  		for _, comment := range strings.Split(comment, "\n") {
    49  			comment = strings.TrimSpace(comment)
    50  
    51  			if strings.HasPrefix(comment, structSkipComment) {
    52  				return true, false
    53  			}
    54  			if strings.HasPrefix(comment, structComment) {
    55  				return false, true
    56  			}
    57  		}
    58  	}
    59  
    60  	return
    61  }
    62  
    63  func (v *visitor) Visit(n ast.Node) (w ast.Visitor) {
    64  	switch n := n.(type) {
    65  	case *ast.Package:
    66  		return v
    67  	case *ast.File:
    68  		v.PkgName = n.Name.String()
    69  		return v
    70  
    71  	case *ast.GenDecl:
    72  		skip, explicit := v.needType(n.Doc)
    73  
    74  		if skip || explicit {
    75  			for _, nc := range n.Specs {
    76  				switch nct := nc.(type) {
    77  				case *ast.TypeSpec:
    78  					nct.Doc = n.Doc
    79  				}
    80  			}
    81  		}
    82  
    83  		return v
    84  	case *ast.TypeSpec:
    85  		skip, explicit := v.needType(n.Doc)
    86  		if skip {
    87  			return nil
    88  		}
    89  		if !explicit && !v.AllStructs {
    90  			return nil
    91  		}
    92  
    93  		v.name = n.Name.String()
    94  
    95  		// Allow to specify non-structs explicitly independent of '-all' flag.
    96  		if explicit {
    97  			v.StructNames = append(v.StructNames, v.name)
    98  			return nil
    99  		}
   100  
   101  		return v
   102  	case *ast.StructType:
   103  		v.StructNames = append(v.StructNames, v.name)
   104  		return nil
   105  	}
   106  	return nil
   107  }
   108  
   109  func (p *Parser) Parse(fname string, isDir bool) error {
   110  	var err error
   111  	if p.PkgPath, err = getPkgPath(fname, isDir); err != nil {
   112  		return err
   113  	}
   114  
   115  	fset := token.NewFileSet()
   116  	if isDir {
   117  		packages, err := parser.ParseDir(fset, fname, excludeTestFiles, parser.ParseComments)
   118  		if err != nil {
   119  			return err
   120  		}
   121  
   122  		for _, pckg := range packages {
   123  			ast.Walk(&visitor{Parser: p}, pckg)
   124  		}
   125  	} else {
   126  		f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
   127  		if err != nil {
   128  			return err
   129  		}
   130  
   131  		ast.Walk(&visitor{Parser: p}, f)
   132  	}
   133  	return nil
   134  }
   135  
   136  func excludeTestFiles(fi os.FileInfo) bool {
   137  	return !strings.HasSuffix(fi.Name(), "_test.go")
   138  }
   139  

View as plain text