| OLD | NEW |
| (Empty) |
| 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 o
f 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 StencilMask(mask uint32) { | |
| 88 // C.glStencilMask(C.GLuint(mask)) | |
| 89 // } | |
| 90 // | |
| 91 // After: | |
| 92 // func StencilMask(mask uint32) { | |
| 93 // defer func() { | |
| 94 // errstr := 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 { | |
| 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 %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 // Insert a defer block for tracing. | |
| 158 fmt.Fprintf(buf, "defer func() {\n") | |
| 159 fmt.Fprintf(buf, "\terrstr := errDrain()\n") | |
| 160 switch fn.Name.Name { | |
| 161 case "GetUniformLocation", "GetAttribLocation": | |
| 162 fmt.Fprintf(buf, "\tr0.name = name\n") | |
| 163 } | |
| 164 fmt.Fprintf(buf, "\tlog.Printf(\"gl.%s(", fn.Name.Name) | |
| 165 for i, p := range paramTypes { | |
| 166 if i > 0 { | |
| 167 fmt.Fprint(buf, ", ") | |
| 168 } | |
| 169 fmt.Fprint(buf, typePrinter(p)) | |
| 170 } | |
| 171 fmt.Fprintf(buf, ") ") | |
| 172 if len(resultTypes) > 1 { | |
| 173 fmt.Fprint(buf, "(") | |
| 174 } | |
| 175 for i, r := range resultTypes { | |
| 176 if i > 0 { | |
| 177 fmt.Fprint(buf, ", ") | |
| 178 } | |
| 179 fmt.Fprint(buf, typePrinter(r)) | |
| 180 } | |
| 181 if len(resultTypes) > 1 { | |
| 182 fmt.Fprint(buf, ") ") | |
| 183 } | |
| 184 fmt.Fprintf(buf, "%%v\"") | |
| 185 for i, p := range paramTypes { | |
| 186 fmt.Fprintf(buf, ", %s", typePrinterArg(p, params[i])) | |
| 187 } | |
| 188 for i, r := range resultTypes { | |
| 189 fmt.Fprintf(buf, ", %s", typePrinterArg(r, results[i])) | |
| 190 } | |
| 191 fmt.Fprintf(buf, ", errstr)\n") | |
| 192 fmt.Fprintf(buf, "}()\n") | |
| 193 | |
| 194 // Print original body of function. | |
| 195 for _, s := range fn.Body.List { | |
| 196 printer.Fprint(buf, fset, s) | |
| 197 fmt.Fprintf(buf, "\n") | |
| 198 } | |
| 199 fmt.Fprintf(buf, "}\n\n") | |
| 200 } | |
| 201 | |
| 202 b, err := format.Source(buf.Bytes()) | |
| 203 if err != nil { | |
| 204 os.Stdout.Write(buf.Bytes()) | |
| 205 die(err) | |
| 206 } | |
| 207 | |
| 208 if *outfile == "" { | |
| 209 os.Stdout.Write(b) | |
| 210 return | |
| 211 } | |
| 212 if err := ioutil.WriteFile(*outfile, b, 0666); err != nil { | |
| 213 die(err) | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 const preamble = `// Copyright 2014 The Go Authors. All rights reserved. | |
| 218 // Use of this source code is governed by a BSD-style | |
| 219 // license that can be found in the LICENSE file. | |
| 220 | |
| 221 // Generated from gl.go using go generate. DO NOT EDIT. | |
| 222 // See doc.go for details. | |
| 223 | |
| 224 // +build linux darwin | |
| 225 // +build gldebug | |
| 226 | |
| 227 package gl | |
| 228 | |
| 229 /* | |
| 230 #include <stdlib.h> | |
| 231 | |
| 232 #ifdef os_linux | |
| 233 #include <GLES2/gl2.h> | |
| 234 #endif | |
| 235 #ifdef os_darwin_arm | |
| 236 #include <OpenGLES/ES2/gl.h> | |
| 237 #endif | |
| 238 #ifdef os_darwin_amd64 | |
| 239 #include <OpenGL/gl3.h> | |
| 240 #endif | |
| 241 */ | |
| 242 import "C" | |
| 243 | |
| 244 import ( | |
| 245 "fmt" | |
| 246 "log" | |
| 247 "unsafe" | |
| 248 ) | |
| 249 | |
| 250 func errDrain() string { | |
| 251 var errs []Enum | |
| 252 for { | |
| 253 e := Enum(C.glGetError()) | |
| 254 if e == 0 { | |
| 255 break | |
| 256 } | |
| 257 errs = append(errs, e) | |
| 258 } | |
| 259 if len(errs) > 0 { | |
| 260 return fmt.Sprintf(" error: %v", errs) | |
| 261 } | |
| 262 return "" | |
| 263 } | |
| 264 | |
| 265 ` | |
| 266 | |
| 267 type entry struct { | |
| 268 name string | |
| 269 value int | |
| 270 } | |
| 271 | |
| 272 // enum builds a list of all GL constants that make up the gl.Enum type. | |
| 273 func enum(f *ast.File) []entry { | |
| 274 var entries []entry | |
| 275 for _, d := range f.Decls { | |
| 276 gendecl, ok := d.(*ast.GenDecl) | |
| 277 if !ok { | |
| 278 continue | |
| 279 } | |
| 280 if gendecl.Tok != token.CONST { | |
| 281 continue | |
| 282 } | |
| 283 for _, s := range gendecl.Specs { | |
| 284 v, ok := s.(*ast.ValueSpec) | |
| 285 if !ok { | |
| 286 continue | |
| 287 } | |
| 288 if len(v.Names) != 1 || len(v.Values) != 1 { | |
| 289 continue | |
| 290 } | |
| 291 val, err := strconv.ParseInt(v.Values[0].(*ast.BasicLit)
.Value, 0, 32) | |
| 292 if err != nil { | |
| 293 log.Fatalf("enum %s: %v", v.Names[0].Name, err) | |
| 294 } | |
| 295 entries = append(entries, entry{v.Names[0].Name, int(val
)}) | |
| 296 } | |
| 297 } | |
| 298 return entries | |
| 299 } | |
| 300 | |
| 301 func dedup(entries []entry) []entry { | |
| 302 // Find all duplicates. Use "%d" as the name of any value with duplicate
s. | |
| 303 seen := make(map[int]int) | |
| 304 for _, e := range entries { | |
| 305 seen[e.value]++ | |
| 306 } | |
| 307 var dedup []entry | |
| 308 for _, e := range entries { | |
| 309 switch seen[e.value] { | |
| 310 case 0: // skip, already here | |
| 311 case 1: | |
| 312 dedup = append(dedup, e) | |
| 313 default: | |
| 314 // value is duplicated | |
| 315 dedup = append(dedup, entry{fmt.Sprintf("%d", e.value),
e.value}) | |
| 316 seen[e.value] = 0 | |
| 317 } | |
| 318 } | |
| 319 return dedup | |
| 320 } | |
| OLD | NEW |