github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/klauspost/cpuid/private-gen.go (about)

     1  // +build ignore
     2  
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"go/ast"
     9  	"go/parser"
    10  	"go/printer"
    11  	"go/token"
    12  	"io"
    13  	"io/ioutil"
    14  	"log"
    15  	"os"
    16  	"reflect"
    17  	"strings"
    18  	"unicode"
    19  	"unicode/utf8"
    20  )
    21  
    22  var inFiles = []string{"cpuid.go", "cpuid_test.go"}
    23  var copyFiles = []string{"cpuid_amd64.s", "cpuid_386.s", "detect_ref.go", "detect_intel.go"}
    24  var fileSet = token.NewFileSet()
    25  var reWrites = []rewrite{
    26  	initRewrite("CPUInfo -> cpuInfo"),
    27  	initRewrite("Vendor -> vendor"),
    28  	initRewrite("Flags -> flags"),
    29  	initRewrite("Detect -> detect"),
    30  	initRewrite("CPU -> cpu"),
    31  }
    32  var excludeNames = map[string]bool{"string": true, "join": true, "trim": true,
    33  	// cpuid_test.go
    34  	"t": true, "println": true, "logf": true, "log": true, "fatalf": true, "fatal": true,
    35  }
    36  
    37  var excludePrefixes = []string{"test", "benchmark"}
    38  
    39  func main() {
    40  	Package := "private"
    41  	parserMode := parser.ParseComments
    42  	exported := make(map[string]rewrite)
    43  	for _, file := range inFiles {
    44  		in, err := os.Open(file)
    45  		if err != nil {
    46  			log.Fatalf("opening input", err)
    47  		}
    48  
    49  		src, err := ioutil.ReadAll(in)
    50  		if err != nil {
    51  			log.Fatalf("reading input", err)
    52  		}
    53  
    54  		astfile, err := parser.ParseFile(fileSet, file, src, parserMode)
    55  		if err != nil {
    56  			log.Fatalf("parsing input", err)
    57  		}
    58  
    59  		for _, rw := range reWrites {
    60  			astfile = rw(astfile)
    61  		}
    62  
    63  		// Inspect the AST and print all identifiers and literals.
    64  		var startDecl token.Pos
    65  		var endDecl token.Pos
    66  		ast.Inspect(astfile, func(n ast.Node) bool {
    67  			var s string
    68  			switch x := n.(type) {
    69  			case *ast.Ident:
    70  				if x.IsExported() {
    71  					t := strings.ToLower(x.Name)
    72  					for _, pre := range excludePrefixes {
    73  						if strings.HasPrefix(t, pre) {
    74  							return true
    75  						}
    76  					}
    77  					if excludeNames[t] != true {
    78  						//if x.Pos() > startDecl && x.Pos() < endDecl {
    79  						exported[x.Name] = initRewrite(x.Name + " -> " + t)
    80  					}
    81  				}
    82  
    83  			case *ast.GenDecl:
    84  				if x.Tok == token.CONST && x.Lparen > 0 {
    85  					startDecl = x.Lparen
    86  					endDecl = x.Rparen
    87  					// fmt.Printf("Decl:%s -> %s\n", fileSet.Position(startDecl), fileSet.Position(endDecl))
    88  				}
    89  			}
    90  			if s != "" {
    91  				fmt.Printf("%s:\t%s\n", fileSet.Position(n.Pos()), s)
    92  			}
    93  			return true
    94  		})
    95  
    96  		for _, rw := range exported {
    97  			astfile = rw(astfile)
    98  		}
    99  
   100  		var buf bytes.Buffer
   101  
   102  		printer.Fprint(&buf, fileSet, astfile)
   103  
   104  		// Remove package documentation and insert information
   105  		s := buf.String()
   106  		ind := strings.Index(buf.String(), "\npackage cpuid")
   107  		s = s[ind:]
   108  		s = "// Generated, DO NOT EDIT,\n" +
   109  			"// but copy it to your own project and rename the package.\n" +
   110  			"// See more at http://yougam/libraries/klauspost/cpuid\n" +
   111  			s
   112  
   113  		outputName := Package + string(os.PathSeparator) + file
   114  
   115  		err = ioutil.WriteFile(outputName, []byte(s), 0644)
   116  		if err != nil {
   117  			log.Fatalf("writing output: %s", err)
   118  		}
   119  		log.Println("Generated", outputName)
   120  	}
   121  
   122  	for _, file := range copyFiles {
   123  		dst := ""
   124  		if strings.HasPrefix(file, "cpuid") {
   125  			dst = Package + string(os.PathSeparator) + file
   126  		} else {
   127  			dst = Package + string(os.PathSeparator) + "cpuid_" + file
   128  		}
   129  		err := copyFile(file, dst)
   130  		if err != nil {
   131  			log.Fatalf("copying file: %s", err)
   132  		}
   133  		log.Println("Copied", dst)
   134  	}
   135  }
   136  
   137  // CopyFile copies a file from src to dst. If src and dst files exist, and are
   138  // the same, then return success. Copy the file contents from src to dst.
   139  func copyFile(src, dst string) (err error) {
   140  	sfi, err := os.Stat(src)
   141  	if err != nil {
   142  		return
   143  	}
   144  	if !sfi.Mode().IsRegular() {
   145  		// cannot copy non-regular files (e.g., directories,
   146  		// symlinks, devices, etc.)
   147  		return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
   148  	}
   149  	dfi, err := os.Stat(dst)
   150  	if err != nil {
   151  		if !os.IsNotExist(err) {
   152  			return
   153  		}
   154  	} else {
   155  		if !(dfi.Mode().IsRegular()) {
   156  			return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
   157  		}
   158  		if os.SameFile(sfi, dfi) {
   159  			return
   160  		}
   161  	}
   162  	err = copyFileContents(src, dst)
   163  	return
   164  }
   165  
   166  // copyFileContents copies the contents of the file named src to the file named
   167  // by dst. The file will be created if it does not already exist. If the
   168  // destination file exists, all it's contents will be replaced by the contents
   169  // of the source file.
   170  func copyFileContents(src, dst string) (err error) {
   171  	in, err := os.Open(src)
   172  	if err != nil {
   173  		return
   174  	}
   175  	defer in.Close()
   176  	out, err := os.Create(dst)
   177  	if err != nil {
   178  		return
   179  	}
   180  	defer func() {
   181  		cerr := out.Close()
   182  		if err == nil {
   183  			err = cerr
   184  		}
   185  	}()
   186  	if _, err = io.Copy(out, in); err != nil {
   187  		return
   188  	}
   189  	err = out.Sync()
   190  	return
   191  }
   192  
   193  type rewrite func(*ast.File) *ast.File
   194  
   195  // Mostly copied from gofmt
   196  func initRewrite(rewriteRule string) rewrite {
   197  	f := strings.Split(rewriteRule, "->")
   198  	if len(f) != 2 {
   199  		fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
   200  		os.Exit(2)
   201  	}
   202  	pattern := parseExpr(f[0], "pattern")
   203  	replace := parseExpr(f[1], "replacement")
   204  	return func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
   205  }
   206  
   207  // parseExpr parses s as an expression.
   208  // It might make sense to expand this to allow statement patterns,
   209  // but there are problems with preserving formatting and also
   210  // with what a wildcard for a statement looks like.
   211  func parseExpr(s, what string) ast.Expr {
   212  	x, err := parser.ParseExpr(s)
   213  	if err != nil {
   214  		fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
   215  		os.Exit(2)
   216  	}
   217  	return x
   218  }
   219  
   220  // Keep this function for debugging.
   221  /*
   222  func dump(msg string, val reflect.Value) {
   223  	fmt.Printf("%s:\n", msg)
   224  	ast.Print(fileSet, val.Interface())
   225  	fmt.Println()
   226  }
   227  */
   228  
   229  // rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
   230  func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
   231  	cmap := ast.NewCommentMap(fileSet, p, p.Comments)
   232  	m := make(map[string]reflect.Value)
   233  	pat := reflect.ValueOf(pattern)
   234  	repl := reflect.ValueOf(replace)
   235  
   236  	var rewriteVal func(val reflect.Value) reflect.Value
   237  	rewriteVal = func(val reflect.Value) reflect.Value {
   238  		// don't bother if val is invalid to start with
   239  		if !val.IsValid() {
   240  			return reflect.Value{}
   241  		}
   242  		for k := range m {
   243  			delete(m, k)
   244  		}
   245  		val = apply(rewriteVal, val)
   246  		if match(m, pat, val) {
   247  			val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
   248  		}
   249  		return val
   250  	}
   251  
   252  	r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
   253  	r.Comments = cmap.Filter(r).Comments() // recreate comments list
   254  	return r
   255  }
   256  
   257  // set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
   258  func set(x, y reflect.Value) {
   259  	// don't bother if x cannot be set or y is invalid
   260  	if !x.CanSet() || !y.IsValid() {
   261  		return
   262  	}
   263  	defer func() {
   264  		if x := recover(); x != nil {
   265  			if s, ok := x.(string); ok &&
   266  				(strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
   267  				// x cannot be set to y - ignore this rewrite
   268  				return
   269  			}
   270  			panic(x)
   271  		}
   272  	}()
   273  	x.Set(y)
   274  }
   275  
   276  // Values/types for special cases.
   277  var (
   278  	objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
   279  	scopePtrNil  = reflect.ValueOf((*ast.Scope)(nil))
   280  
   281  	identType     = reflect.TypeOf((*ast.Ident)(nil))
   282  	objectPtrType = reflect.TypeOf((*ast.Object)(nil))
   283  	positionType  = reflect.TypeOf(token.NoPos)
   284  	callExprType  = reflect.TypeOf((*ast.CallExpr)(nil))
   285  	scopePtrType  = reflect.TypeOf((*ast.Scope)(nil))
   286  )
   287  
   288  // apply replaces each AST field x in val with f(x), returning val.
   289  // To avoid extra conversions, f operates on the reflect.Value form.
   290  func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
   291  	if !val.IsValid() {
   292  		return reflect.Value{}
   293  	}
   294  
   295  	// *ast.Objects introduce cycles and are likely incorrect after
   296  	// rewrite; don't follow them but replace with nil instead
   297  	if val.Type() == objectPtrType {
   298  		return objectPtrNil
   299  	}
   300  
   301  	// similarly for scopes: they are likely incorrect after a rewrite;
   302  	// replace them with nil
   303  	if val.Type() == scopePtrType {
   304  		return scopePtrNil
   305  	}
   306  
   307  	switch v := reflect.Indirect(val); v.Kind() {
   308  	case reflect.Slice:
   309  		for i := 0; i < v.Len(); i++ {
   310  			e := v.Index(i)
   311  			set(e, f(e))
   312  		}
   313  	case reflect.Struct:
   314  		for i := 0; i < v.NumField(); i++ {
   315  			e := v.Field(i)
   316  			set(e, f(e))
   317  		}
   318  	case reflect.Interface:
   319  		e := v.Elem()
   320  		set(v, f(e))
   321  	}
   322  	return val
   323  }
   324  
   325  func isWildcard(s string) bool {
   326  	rune, size := utf8.DecodeRuneInString(s)
   327  	return size == len(s) && unicode.IsLower(rune)
   328  }
   329  
   330  // match returns true if pattern matches val,
   331  // recording wildcard submatches in m.
   332  // If m == nil, match checks whether pattern == val.
   333  func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
   334  	// Wildcard matches any expression.  If it appears multiple
   335  	// times in the pattern, it must match the same expression
   336  	// each time.
   337  	if m != nil && pattern.IsValid() && pattern.Type() == identType {
   338  		name := pattern.Interface().(*ast.Ident).Name
   339  		if isWildcard(name) && val.IsValid() {
   340  			// wildcards only match valid (non-nil) expressions.
   341  			if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
   342  				if old, ok := m[name]; ok {
   343  					return match(nil, old, val)
   344  				}
   345  				m[name] = val
   346  				return true
   347  			}
   348  		}
   349  	}
   350  
   351  	// Otherwise, pattern and val must match recursively.
   352  	if !pattern.IsValid() || !val.IsValid() {
   353  		return !pattern.IsValid() && !val.IsValid()
   354  	}
   355  	if pattern.Type() != val.Type() {
   356  		return false
   357  	}
   358  
   359  	// Special cases.
   360  	switch pattern.Type() {
   361  	case identType:
   362  		// For identifiers, only the names need to match
   363  		// (and none of the other *ast.Object information).
   364  		// This is a common case, handle it all here instead
   365  		// of recursing down any further via reflection.
   366  		p := pattern.Interface().(*ast.Ident)
   367  		v := val.Interface().(*ast.Ident)
   368  		return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
   369  	case objectPtrType, positionType:
   370  		// object pointers and token positions always match
   371  		return true
   372  	case callExprType:
   373  		// For calls, the Ellipsis fields (token.Position) must
   374  		// match since that is how f(x) and f(x...) are different.
   375  		// Check them here but fall through for the remaining fields.
   376  		p := pattern.Interface().(*ast.CallExpr)
   377  		v := val.Interface().(*ast.CallExpr)
   378  		if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
   379  			return false
   380  		}
   381  	}
   382  
   383  	p := reflect.Indirect(pattern)
   384  	v := reflect.Indirect(val)
   385  	if !p.IsValid() || !v.IsValid() {
   386  		return !p.IsValid() && !v.IsValid()
   387  	}
   388  
   389  	switch p.Kind() {
   390  	case reflect.Slice:
   391  		if p.Len() != v.Len() {
   392  			return false
   393  		}
   394  		for i := 0; i < p.Len(); i++ {
   395  			if !match(m, p.Index(i), v.Index(i)) {
   396  				return false
   397  			}
   398  		}
   399  		return true
   400  
   401  	case reflect.Struct:
   402  		for i := 0; i < p.NumField(); i++ {
   403  			if !match(m, p.Field(i), v.Field(i)) {
   404  				return false
   405  			}
   406  		}
   407  		return true
   408  
   409  	case reflect.Interface:
   410  		return match(m, p.Elem(), v.Elem())
   411  	}
   412  
   413  	// Handle token integers, etc.
   414  	return p.Interface() == v.Interface()
   415  }
   416  
   417  // subst returns a copy of pattern with values from m substituted in place
   418  // of wildcards and pos used as the position of tokens from the pattern.
   419  // if m == nil, subst returns a copy of pattern and doesn't change the line
   420  // number information.
   421  func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
   422  	if !pattern.IsValid() {
   423  		return reflect.Value{}
   424  	}
   425  
   426  	// Wildcard gets replaced with map value.
   427  	if m != nil && pattern.Type() == identType {
   428  		name := pattern.Interface().(*ast.Ident).Name
   429  		if isWildcard(name) {
   430  			if old, ok := m[name]; ok {
   431  				return subst(nil, old, reflect.Value{})
   432  			}
   433  		}
   434  	}
   435  
   436  	if pos.IsValid() && pattern.Type() == positionType {
   437  		// use new position only if old position was valid in the first place
   438  		if old := pattern.Interface().(token.Pos); !old.IsValid() {
   439  			return pattern
   440  		}
   441  		return pos
   442  	}
   443  
   444  	// Otherwise copy.
   445  	switch p := pattern; p.Kind() {
   446  	case reflect.Slice:
   447  		v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
   448  		for i := 0; i < p.Len(); i++ {
   449  			v.Index(i).Set(subst(m, p.Index(i), pos))
   450  		}
   451  		return v
   452  
   453  	case reflect.Struct:
   454  		v := reflect.New(p.Type()).Elem()
   455  		for i := 0; i < p.NumField(); i++ {
   456  			v.Field(i).Set(subst(m, p.Field(i), pos))
   457  		}
   458  		return v
   459  
   460  	case reflect.Ptr:
   461  		v := reflect.New(p.Type()).Elem()
   462  		if elem := p.Elem(); elem.IsValid() {
   463  			v.Set(subst(m, elem, pos).Addr())
   464  		}
   465  		return v
   466  
   467  	case reflect.Interface:
   468  		v := reflect.New(p.Type()).Elem()
   469  		if elem := p.Elem(); elem.IsValid() {
   470  			v.Set(subst(m, elem, pos))
   471  		}
   472  		return v
   473  	}
   474  
   475  	return pattern
   476  }