github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/gl/gendebug.go (about)

     1  // Copyright 2014 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build ignore
     6  
     7  // The gendebug program takes gl.go and generates a version of it
     8  // where each function includes tracing code that writes its arguments
     9  // to the standard log.
    10  package main
    11  
    12  import (
    13  	"bytes"
    14  	"flag"
    15  	"fmt"
    16  	"go/ast"
    17  	"go/format"
    18  	"go/parser"
    19  	"go/printer"
    20  	"go/token"
    21  	"io/ioutil"
    22  	"log"
    23  	"os"
    24  	"strconv"
    25  )
    26  
    27  var outfile = flag.String("o", "", "result will be written to the file instead of stdout.")
    28  
    29  var fset = new(token.FileSet)
    30  
    31  func typeString(t ast.Expr) string {
    32  	buf := new(bytes.Buffer)
    33  	printer.Fprint(buf, fset, t)
    34  	return buf.String()
    35  }
    36  
    37  func typePrinter(t string) string {
    38  	switch t {
    39  	case "[]float32", "[]byte":
    40  		return "len(%d)"
    41  	}
    42  	return "%v"
    43  }
    44  
    45  func typePrinterArg(t, name string) string {
    46  	switch t {
    47  	case "[]float32", "[]byte":
    48  		return "len(" + name + ")"
    49  	}
    50  	return name
    51  }
    52  
    53  func die(err error) {
    54  	fmt.Fprintf(os.Stderr, err.Error())
    55  	os.Exit(1)
    56  }
    57  
    58  func main() {
    59  	flag.Parse()
    60  
    61  	f, err := parser.ParseFile(fset, "consts.go", nil, parser.ParseComments)
    62  	if err != nil {
    63  		die(err)
    64  	}
    65  	entries := enum(f)
    66  
    67  	f, err = parser.ParseFile(fset, "gl.go", nil, parser.ParseComments)
    68  	if err != nil {
    69  		die(err)
    70  	}
    71  
    72  	buf := new(bytes.Buffer)
    73  
    74  	fmt.Fprint(buf, preamble)
    75  
    76  	fmt.Fprintf(buf, "func (v Enum) String() string {\n")
    77  	fmt.Fprintf(buf, "\tswitch v {\n")
    78  	for _, e := range dedup(entries) {
    79  		fmt.Fprintf(buf, "\tcase 0x%x: return %q\n", e.value, e.name)
    80  	}
    81  	fmt.Fprintf(buf, "\t%s\n", `default: return fmt.Sprintf("gl.Enum(0x%x)", uint32(v))`)
    82  	fmt.Fprintf(buf, "\t}\n")
    83  	fmt.Fprintf(buf, "}\n\n")
    84  
    85  	for _, d := range f.Decls {
    86  		// Before:
    87  		// func (ctx *context) StencilMask(mask uint32) {
    88  		//	C.glStencilMask(C.GLuint(mask))
    89  		// }
    90  		//
    91  		// After:
    92  		// func (ctx *context) StencilMask(mask uint32) {
    93  		// 	defer func() {
    94  		// 		errstr := ctx.errDrain()
    95  		// 		log.Printf("gl.StencilMask(%v) %v", mask, errstr)
    96  		//	}()
    97  		//	C.glStencilMask(C.GLuint(mask))
    98  		// }
    99  		fn, ok := d.(*ast.FuncDecl)
   100  		if !ok {
   101  			continue
   102  		}
   103  		if fn.Recv == nil || fn.Recv.List[0].Names[0].Name != "ctx" {
   104  			continue
   105  		}
   106  
   107  		var (
   108  			params      []string
   109  			paramTypes  []string
   110  			results     []string
   111  			resultTypes []string
   112  		)
   113  
   114  		// Print function signature.
   115  		fmt.Fprintf(buf, "func (ctx *context) %s(", fn.Name.Name)
   116  		for i, p := range fn.Type.Params.List {
   117  			if i > 0 {
   118  				fmt.Fprint(buf, ", ")
   119  			}
   120  			ty := typeString(p.Type)
   121  			for i, n := range p.Names {
   122  				if i > 0 {
   123  					fmt.Fprint(buf, ", ")
   124  				}
   125  				fmt.Fprintf(buf, "%s ", n.Name)
   126  				params = append(params, n.Name)
   127  				paramTypes = append(paramTypes, ty)
   128  			}
   129  			fmt.Fprint(buf, ty)
   130  		}
   131  		fmt.Fprintf(buf, ") (")
   132  		if fn.Type.Results != nil {
   133  			for i, r := range fn.Type.Results.List {
   134  				if i > 0 {
   135  					fmt.Fprint(buf, ", ")
   136  				}
   137  				ty := typeString(r.Type)
   138  				if len(r.Names) == 0 {
   139  					name := fmt.Sprintf("r%d", i)
   140  					fmt.Fprintf(buf, "%s ", name)
   141  					results = append(results, name)
   142  					resultTypes = append(resultTypes, ty)
   143  				}
   144  				for i, n := range r.Names {
   145  					if i > 0 {
   146  						fmt.Fprint(buf, ", ")
   147  					}
   148  					fmt.Fprintf(buf, "%s ", n.Name)
   149  					results = append(results, n.Name)
   150  					resultTypes = append(resultTypes, ty)
   151  				}
   152  				fmt.Fprint(buf, ty)
   153  			}
   154  		}
   155  		fmt.Fprintf(buf, ") {\n")
   156  
   157  		// gl.GetError is used by errDrain, which will be made part of
   158  		// all functions. So do not apply it to gl.GetError to avoid
   159  		// infinite recursion.
   160  		skip := fn.Name.Name == "GetError"
   161  
   162  		if !skip {
   163  			// Insert a defer block for tracing.
   164  			fmt.Fprintf(buf, "defer func() {\n")
   165  			fmt.Fprintf(buf, "\terrstr := ctx.errDrain()\n")
   166  			switch fn.Name.Name {
   167  			case "GetUniformLocation", "GetAttribLocation":
   168  				fmt.Fprintf(buf, "\tr0.name = name\n")
   169  			}
   170  			fmt.Fprintf(buf, "\tlog.Printf(\"gl.%s(", fn.Name.Name)
   171  			for i, p := range paramTypes {
   172  				if i > 0 {
   173  					fmt.Fprint(buf, ", ")
   174  				}
   175  				fmt.Fprint(buf, typePrinter(p))
   176  			}
   177  			fmt.Fprintf(buf, ") ")
   178  			if len(resultTypes) > 1 {
   179  				fmt.Fprint(buf, "(")
   180  			}
   181  			for i, r := range resultTypes {
   182  				if i > 0 {
   183  					fmt.Fprint(buf, ", ")
   184  				}
   185  				fmt.Fprint(buf, typePrinter(r))
   186  			}
   187  			if len(resultTypes) > 1 {
   188  				fmt.Fprint(buf, ") ")
   189  			}
   190  			fmt.Fprintf(buf, "%%v\"")
   191  			for i, p := range paramTypes {
   192  				fmt.Fprintf(buf, ", %s", typePrinterArg(p, params[i]))
   193  			}
   194  			for i, r := range resultTypes {
   195  				fmt.Fprintf(buf, ", %s", typePrinterArg(r, results[i]))
   196  			}
   197  			fmt.Fprintf(buf, ", errstr)\n")
   198  			fmt.Fprintf(buf, "}()\n")
   199  		}
   200  
   201  		// Print original body of function.
   202  		for _, s := range fn.Body.List {
   203  			if c := enqueueCall(s); c != nil {
   204  				c.Fun.(*ast.SelectorExpr).Sel.Name = "enqueueDebug"
   205  				setEnqueueBlocking(c)
   206  			}
   207  			printer.Fprint(buf, fset, s)
   208  			fmt.Fprintf(buf, "\n")
   209  		}
   210  		fmt.Fprintf(buf, "}\n\n")
   211  	}
   212  
   213  	b, err := format.Source(buf.Bytes())
   214  	if err != nil {
   215  		os.Stdout.Write(buf.Bytes())
   216  		die(err)
   217  	}
   218  
   219  	if *outfile == "" {
   220  		os.Stdout.Write(b)
   221  		return
   222  	}
   223  	if err := ioutil.WriteFile(*outfile, b, 0666); err != nil {
   224  		die(err)
   225  	}
   226  }
   227  
   228  func enqueueCall(stmt ast.Stmt) *ast.CallExpr {
   229  	exprStmt, ok := stmt.(*ast.ExprStmt)
   230  	if !ok {
   231  		return nil
   232  	}
   233  	call, ok := exprStmt.X.(*ast.CallExpr)
   234  	if !ok {
   235  		return nil
   236  	}
   237  	fun, ok := call.Fun.(*ast.SelectorExpr)
   238  	if !ok {
   239  		return nil
   240  	}
   241  	if fun.Sel.Name != "enqueue" {
   242  		return nil
   243  	}
   244  	return call
   245  }
   246  
   247  func setEnqueueBlocking(c *ast.CallExpr) {
   248  	lit := c.Args[0].(*ast.CompositeLit)
   249  	for _, elt := range lit.Elts {
   250  		kv := elt.(*ast.KeyValueExpr)
   251  		if kv.Key.(*ast.Ident).Name == "blocking" {
   252  			kv.Value = &ast.Ident{Name: "true"}
   253  			return
   254  		}
   255  	}
   256  	lit.Elts = append(lit.Elts, &ast.KeyValueExpr{
   257  		Key: &ast.Ident{
   258  			NamePos: lit.Rbrace,
   259  			Name:    "blocking",
   260  		},
   261  		Value: &ast.Ident{Name: "true"},
   262  	})
   263  }
   264  
   265  const preamble = `// Copyright 2014 The Go Authors.  All rights reserved.
   266  // Use of this source code is governed by a BSD-style
   267  // license that can be found in the LICENSE file.
   268  
   269  // Generated from gl.go using go generate. DO NOT EDIT.
   270  // See doc.go for details.
   271  
   272  // +build linux darwin windows
   273  // +build gldebug
   274  
   275  package gl
   276  
   277  import (
   278  	"fmt"
   279  	"log"
   280  	"math"
   281  	"sync/atomic"
   282  	"unsafe"
   283  )
   284  
   285  func (ctx *context) errDrain() string {
   286  	var errs []Enum
   287  	for {
   288  		e := ctx.GetError()
   289  		if e == 0 {
   290  			break
   291  		}
   292  		errs = append(errs, e)
   293  	}
   294  	if len(errs) > 0 {
   295  		return fmt.Sprintf(" error: %v", errs)
   296  	}
   297  	return ""
   298  }
   299  
   300  func (ctx *context) enqueueDebug(c call) uintptr {
   301  	numCalls := atomic.AddInt32(&ctx.debug, 1)
   302  	if numCalls > 1 {
   303  		panic("concurrent calls made to the same GL context")
   304  	}
   305  	defer func() {
   306  		if atomic.AddInt32(&ctx.debug, -1) > 0 {
   307  			select {} // block so you see us in the panic
   308  		}
   309  	}()
   310  
   311  	return ctx.enqueue(c)
   312  }
   313  
   314  `
   315  
   316  type entry struct {
   317  	name  string
   318  	value int
   319  }
   320  
   321  // enum builds a list of all GL constants that make up the gl.Enum type.
   322  func enum(f *ast.File) []entry {
   323  	var entries []entry
   324  	for _, d := range f.Decls {
   325  		gendecl, ok := d.(*ast.GenDecl)
   326  		if !ok {
   327  			continue
   328  		}
   329  		if gendecl.Tok != token.CONST {
   330  			continue
   331  		}
   332  		for _, s := range gendecl.Specs {
   333  			v, ok := s.(*ast.ValueSpec)
   334  			if !ok {
   335  				continue
   336  			}
   337  			if len(v.Names) != 1 || len(v.Values) != 1 {
   338  				continue
   339  			}
   340  			val, err := strconv.ParseInt(v.Values[0].(*ast.BasicLit).Value, 0, 32)
   341  			if err != nil {
   342  				log.Fatalf("enum %s: %v", v.Names[0].Name, err)
   343  			}
   344  			entries = append(entries, entry{v.Names[0].Name, int(val)})
   345  		}
   346  	}
   347  	return entries
   348  }
   349  
   350  func dedup(entries []entry) []entry {
   351  	// Find all duplicates. Use "%d" as the name of any value with duplicates.
   352  	seen := make(map[int]int)
   353  	for _, e := range entries {
   354  		seen[e.value]++
   355  	}
   356  	var dedup []entry
   357  	for _, e := range entries {
   358  		switch seen[e.value] {
   359  		case 0: // skip, already here
   360  		case 1:
   361  			dedup = append(dedup, e)
   362  		default:
   363  			// value is duplicated
   364  			dedup = append(dedup, entry{fmt.Sprintf("%d", e.value), e.value})
   365  			seen[e.value] = 0
   366  		}
   367  	}
   368  	return dedup
   369  }