func main()

in gl/gendebug.go [667:842]


func main() {
	flag.Parse()

	f, err := parser.ParseFile(fset, "consts.go", nil, parser.ParseComments)
	if err != nil {
		die(err)
	}
	entries := enum(f)

	f, err = parser.ParseFile(fset, "gl.go", nil, parser.ParseComments)
	if err != nil {
		die(err)
	}

	buf := new(bytes.Buffer)

	fmt.Fprint(buf, preamble)

	fmt.Fprintf(buf, "func (v Enum) String() string {\n")
	fmt.Fprintf(buf, "\tswitch v {\n")
	for _, e := range dedup(entries) {
		fmt.Fprintf(buf, "\tcase 0x%x: return %q\n", e.value, e.name)
	}
	fmt.Fprintf(buf, "\t%s\n", `default: return fmt.Sprintf("gl.Enum(0x%x)", uint32(v))`)
	fmt.Fprintf(buf, "\t}\n")
	fmt.Fprintf(buf, "}\n\n")

	for _, d := range f.Decls {
		// Before:
		// func (ctx *context) StencilMask(mask uint32) {
		//	C.glStencilMask(C.GLuint(mask))
		// }
		//
		// After:
		// func (ctx *context) StencilMask(mask uint32) {
		// 	defer func() {
		// 		errstr := ctx.errDrain()
		// 		log.Printf("gl.StencilMask(%v) %v", mask, errstr)
		//	}()
		//	C.glStencilMask(C.GLuint(mask))
		// }
		fn, ok := d.(*ast.FuncDecl)
		if !ok {
			continue
		}
		if fn.Recv == nil || fn.Recv.List[0].Names[0].Name != "ctx" {
			continue
		}
		tname := "<unknown>"
		t := fn.Recv.List[0].Type
		if star, ok := t.(*ast.StarExpr); ok {
			tname = "*" + star.X.(*ast.Ident).Name
		} else if t, ok := t.(*ast.Ident); ok {
			tname = t.Name
		}

		var (
			params      []string
			paramTypes  []string
			results     []string
			resultTypes []string
		)

		// Print function signature.
		fmt.Fprintf(buf, "func (ctx %s) %s(", tname, fn.Name.Name)
		for i, p := range fn.Type.Params.List {
			if i > 0 {
				fmt.Fprint(buf, ", ")
			}
			ty := typeString(p.Type)
			for i, n := range p.Names {
				if i > 0 {
					fmt.Fprint(buf, ", ")
				}
				fmt.Fprintf(buf, "%s ", n.Name)
				params = append(params, n.Name)
				paramTypes = append(paramTypes, ty)
			}
			fmt.Fprint(buf, ty)
		}
		fmt.Fprintf(buf, ") (")
		if fn.Type.Results != nil {
			for i, r := range fn.Type.Results.List {
				if i > 0 {
					fmt.Fprint(buf, ", ")
				}
				ty := typeString(r.Type)
				if len(r.Names) == 0 {
					name := fmt.Sprintf("r%d", i)
					fmt.Fprintf(buf, "%s ", name)
					results = append(results, name)
					resultTypes = append(resultTypes, ty)
				}
				for i, n := range r.Names {
					if i > 0 {
						fmt.Fprint(buf, ", ")
					}
					fmt.Fprintf(buf, "%s ", n.Name)
					results = append(results, n.Name)
					resultTypes = append(resultTypes, ty)
				}
				fmt.Fprint(buf, ty)
			}
		}
		fmt.Fprintf(buf, ") {\n")

		// gl.GetError is used by errDrain, which will be made part of
		// all functions. So do not apply it to gl.GetError to avoid
		// infinite recursion.
		skip := fn.Name.Name == "GetError"

		if !skip {
			// Insert a defer block for tracing.
			fmt.Fprintf(buf, "defer func() {\n")
			fmt.Fprintf(buf, "\terrstr := ctx.errDrain()\n")
			switch fn.Name.Name {
			case "GetUniformLocation", "GetAttribLocation":
				fmt.Fprintf(buf, "\tr0.name = name\n")
			}
			fmt.Fprintf(buf, "\tlog.Printf(\"gl.%s(", fn.Name.Name)
			for i, p := range paramTypes {
				if i > 0 {
					fmt.Fprint(buf, ", ")
				}
				fmt.Fprint(buf, typePrinter(p))
			}
			fmt.Fprintf(buf, ") ")
			if len(resultTypes) > 1 {
				fmt.Fprint(buf, "(")
			}
			for i, r := range resultTypes {
				if i > 0 {
					fmt.Fprint(buf, ", ")
				}
				fmt.Fprint(buf, typePrinter(r))
			}
			if len(resultTypes) > 1 {
				fmt.Fprint(buf, ") ")
			}
			fmt.Fprintf(buf, "%%v\"")
			for i, p := range paramTypes {
				fmt.Fprintf(buf, ", %s", typePrinterArg(p, params[i]))
			}
			for i, r := range resultTypes {
				fmt.Fprintf(buf, ", %s", typePrinterArg(r, results[i]))
			}
			fmt.Fprintf(buf, ", errstr)\n")
			fmt.Fprintf(buf, "}()\n")
		}

		// Print original body of function.
		for _, s := range fn.Body.List {
			if c := enqueueCall(s); c != nil {
				c.Fun.(*ast.SelectorExpr).Sel.Name = "enqueueDebug"
				setEnqueueBlocking(c)
			}
			printer.Fprint(buf, fset, s)
			fmt.Fprintf(buf, "\n")
		}
		fmt.Fprintf(buf, "}\n\n")
	}

	b, err := format.Source(buf.Bytes())
	if err != nil {
		os.Stdout.Write(buf.Bytes())
		die(err)
	}

	if *outfile == "" {
		os.Stdout.Write(b)
		return
	}
	if err := ioutil.WriteFile(*outfile, b, 0666); err != nil {
		die(err)
	}
}