go-hep.org/x/hep@v0.38.1/groot/rdict/gen_streamer.go (about) 1 // Copyright ©2019 The go-hep 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 package rdict 6 7 import ( 8 "bytes" 9 "fmt" 10 "go/format" 11 "go/types" 12 "log" 13 "reflect" 14 15 "go-hep.org/x/hep/groot/rmeta" 16 "golang.org/x/tools/go/packages" 17 ) 18 19 // genStreamer holds the state of the ROOT streamer generation. 20 type genStreamer struct { 21 buf *bytes.Buffer 22 pkg *types.Package 23 24 // set of imported packages. 25 // usually: "encoding/binary", "math" 26 imps map[string]int 27 28 verbose bool // enable verbose mode 29 30 binMa *types.Interface // encoding.BinaryMarshaler 31 binUn *types.Interface // encoding.BinaryUnmarshaler 32 rvers *types.Interface // rbytes.RVersioner 33 34 gosizes types.Sizes 35 } 36 37 func importPkg(p string) (*types.Package, error) { 38 cfg := &packages.Config{Mode: packages.NeedTypes | packages.NeedTypesInfo | packages.NeedTypesSizes | packages.NeedDeps} 39 pkgs, err := packages.Load(cfg, p) 40 if err != nil { 41 return nil, fmt.Errorf("could not load package %q: %w", p, err) 42 } 43 44 return pkgs[0].Types, nil 45 } 46 47 // NewGenStreamer returns a new code generator for package p, 48 // where p is the package's import path. 49 func NewGenStreamer(p string, verbose bool) (Generator, error) { 50 pkg, err := importPkg(p) 51 if err != nil { 52 return nil, err 53 } 54 g := &genStreamer{ 55 buf: new(bytes.Buffer), 56 pkg: pkg, 57 imps: map[string]int{ 58 "go-hep.org/x/hep/groot/rbytes": 1, 59 "go-hep.org/x/hep/groot/rdict": 1, 60 "go-hep.org/x/hep/groot/rmeta": 1, 61 }, 62 verbose: verbose, 63 } 64 65 err = g.init() 66 if err != nil { 67 return nil, err 68 } 69 70 return g, nil 71 } 72 73 func (g *genStreamer) init() error { 74 pkg, err := importPkg("encoding") 75 if err != nil { 76 return fmt.Errorf("rdict: could not find package \"encoding\": %w", err) 77 } 78 79 o := pkg.Scope().Lookup("BinaryMarshaler") 80 if o == nil { 81 return fmt.Errorf("rdict: could not find interface encoding.BinaryMarshaler") 82 } 83 g.binMa = o.(*types.TypeName).Type().Underlying().(*types.Interface) 84 85 o = pkg.Scope().Lookup("BinaryUnmarshaler") 86 if o == nil { 87 return fmt.Errorf("rdict: could not find interface encoding.BinaryUnmarshaler") 88 } 89 g.binUn = o.(*types.TypeName).Type().Underlying().(*types.Interface) 90 91 pkg, err = importPkg("go-hep.org/x/hep/groot/rbytes") 92 if err != nil { 93 return fmt.Errorf("rdict: could not find package %q: %w", "go-hep.org/x/hep/groot/rbytes", err) 94 } 95 96 o = pkg.Scope().Lookup("RVersioner") 97 if o == nil { 98 return fmt.Errorf("rdict: could not find interface rbytes.RVersioner") 99 } 100 g.rvers = o.(*types.TypeName).Type().Underlying().(*types.Interface) 101 102 sz := int64(reflect.TypeOf(int(0)).Size()) 103 g.gosizes = &types.StdSizes{WordSize: sz, MaxAlign: sz} 104 return nil 105 } 106 107 func (g *genStreamer) printf(format string, args ...any) { 108 fmt.Fprintf(g.buf, format, args...) 109 } 110 111 // Generate implements rdict.Generator 112 func (g *genStreamer) Generate(typeName string) error { 113 scope := g.pkg.Scope() 114 obj := scope.Lookup(typeName) 115 if obj == nil { 116 return fmt.Errorf("no such type %q in package %q", typeName, g.pkg.Path()+"/"+g.pkg.Name()) 117 } 118 119 tn, ok := obj.(*types.TypeName) 120 if !ok { 121 return fmt.Errorf("%q is not a type (%v)", typeName, obj) 122 } 123 124 typ, ok := tn.Type().Underlying().(*types.Struct) 125 if !ok { 126 return fmt.Errorf("%q is not a named struct (%v)", typeName, tn) 127 } 128 if g.verbose { 129 log.Printf("typ: %q: %+v\n", typeName, typ) 130 } 131 132 if !types.Implements(tn.Type(), g.rvers) && !types.Implements(types.NewPointer(tn.Type()), g.rvers) { 133 g.genRVersioner(typ, typeName) 134 } 135 136 g.genStreamer(typ, typeName) 137 g.genMarshal(typ, typeName) 138 // g.genUnmarshal(typ, typeName) 139 140 return nil 141 } 142 143 func (g *genStreamer) genMarshal(t types.Type, typeName string) { 144 g.printf(`// MarshalROOT implements rbytes.Marshaler 145 func (o *%[1]s) MarshalROOT(w *rbytes.WBuffer) (int, error) { 146 if w.Err() != nil { 147 return 0, w.Err() 148 } 149 150 hdr := w.WriteHeader(o.Class(), o.RVersion()) 151 152 `, 153 typeName, 154 ) 155 156 typ := t.Underlying().(*types.Struct) 157 for i := range typ.NumFields() { 158 ft := typ.Field(i) 159 n := ft.Name() // no `groot:"foo"` redirection. 160 g.genMarshalType(ft.Type(), n) 161 } 162 163 g.printf("\n\treturn w.SetHeader(hdr)\n}\n\n") 164 } 165 166 // func (g *genStreamer) genUnmarshal(t types.Type, typeName string) { 167 // g.printf(`// UnmarshalROOT implements rbytes.Unmarshaler 168 // func (o *%[1]s) UnmarshalROOT(r *rbytes.RBuffer) error { 169 // rs, err := rdict.RStreamer(r, o) 170 // if err != nil { 171 // return err 172 // } 173 // return rs.RStreamROOT(r) 174 // } 175 // `, 176 // typeName, 177 // ) 178 // } 179 180 func (g *genStreamer) genRVersioner(t types.Type, typeName string) { 181 g.printf("func (*%s) RVersion() int16 { return 1 }\n\n", typeName) 182 } 183 184 func (g *genStreamer) genStreamer(t types.Type, typeName string) { 185 g.printf(`func init() { 186 // Streamer for %[1]s. 187 rdict.StreamerInfos.Add(rdict.NewStreamerInfo(%[2]q, int(((*%[1]s)(nil)).RVersion()), []rbytes.StreamerElement{ 188 `, 189 typeName, 190 g.pkg.Path()+"."+typeName, 191 ) 192 193 typ := t.Underlying().(*types.Struct) 194 for i := range typ.NumFields() { 195 ft := typ.Field(i) 196 n := ft.Name() 197 if tag := typ.Tag(i); tag != "" { 198 nn := reflect.StructTag(tag).Get("groot") 199 if nn != "" { 200 n = nn 201 } 202 } 203 g.genStreamerType(ft.Type(), n) 204 } 205 206 g.printf("}))\n}\n\n") 207 } 208 209 func (g *genStreamer) genStreamerType(t types.Type, n string) { 210 ut := t.Underlying() 211 switch ut := ut.(type) { 212 case *types.Basic: 213 switch kind := ut.Kind(); kind { 214 case types.Bool: 215 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 216 case types.Uint8: 217 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 218 case types.Uint16: 219 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 220 case types.Uint32, types.Uint: 221 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 222 case types.Uint64: 223 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 224 case types.Int8: 225 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 226 case types.Int16: 227 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 228 case types.Int32, types.Int: 229 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 230 case types.Int64: 231 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 232 case types.Float32: 233 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 234 case types.Float64: 235 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 236 case types.Complex64: 237 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 238 239 case types.Complex128: 240 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 241 242 case types.String: 243 g.printf("%s,\n", g.se(ut, n, "", 0)) 244 245 default: 246 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 247 } 248 249 case *types.Array: 250 // FIXME(sbinet): collect+visit element type. 251 switch eut := ut.Elem().Underlying().(type) { 252 case *types.Basic: 253 switch kind := eut.Kind(); kind { 254 default: 255 g.printf( 256 "&rdict.StreamerBasicType{StreamerElement: %s},\n", 257 g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()), 258 ) 259 case types.String: 260 g.printf( 261 "%s,\n", 262 g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()), 263 ) 264 } 265 default: 266 g.printf( 267 "%s\n", 268 g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()), 269 ) 270 } 271 case *types.Slice: 272 // FIXME(sbinet): collect+visit element type. 273 g.printf("rdict.NewStreamerSTL(%q, rmeta.STLvector, rmeta.%v),\n", n, gotype2RMeta(ut.Elem())) 274 275 case *types.Struct: 276 g.imps["go-hep.org/x/hep/groot/rbase"]++ 277 g.printf( 278 "&rdict.StreamerObjectAny{StreamerElement:rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Any,\nSize: %[4]d,\nEName:rdict.GoName2Cxx(%[3]q),\n}.New()},\n", 279 n, "", 280 t.String(), g.gosizes.Sizeof(ut), 281 ) 282 283 default: 284 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 285 } 286 } 287 288 func (g *genStreamer) wt(t types.Type, n, meth, arr string) { 289 ut := t.Underlying() 290 switch ut := ut.(type) { 291 case *types.Basic: 292 switch kind := ut.Kind(); kind { 293 case types.Bool: 294 g.printf("w.Write%sBool(o.%s%s)\n", meth, n, arr) 295 case types.Uint8: 296 g.printf("w.Write%sU8(o.%s%s)\n", meth, n, arr) 297 case types.Uint16: 298 g.printf("w.Write%sU16(o.%s%s)\n", meth, n, arr) 299 case types.Uint32: 300 g.printf("w.Write%sU32(o.%s%s)\n", meth, n, arr) 301 case types.Uint64: 302 g.printf("w.Write%sU64(o.%s%s)\n", meth, n, arr) 303 case types.Int8: 304 g.printf("w.Write%sI8(o.%s%s)\n", meth, n, arr) 305 case types.Int16: 306 g.printf("w.Write%sI16(o.%s%s)\n", meth, n, arr) 307 case types.Int32: 308 g.printf("w.Write%sI32(o.%s%s)\n", meth, n, arr) 309 case types.Int64: 310 g.printf("w.Write%sI64(o.%s%s)\n", meth, n, arr) 311 case types.Float32: 312 g.printf("w.Write%sF32(o.%s%s)\n", meth, n, arr) 313 case types.Float64: 314 g.printf("w.Write%sF64(o.%s%s)\n", meth, n, arr) 315 316 case types.Uint: 317 g.printf("w.Write%sU64(uint64(o.%s%s))\n", meth, n, arr) 318 case types.Int: 319 g.printf("w.Write%sI64(int64(o.%s%s))\n", meth, n, arr) 320 321 case types.Complex64: 322 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 323 case types.Complex128: 324 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 325 326 case types.String: 327 g.printf("w.Write%sString(o.%s%s)\n", meth, n, arr) 328 329 default: 330 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 331 } 332 333 case *types.Struct: 334 g.printf("w.WriteObject(&o.%s)\n", n) 335 336 default: 337 log.Fatalf("unhandled marshal type: %v (underlying %v)", t, ut) 338 } 339 } 340 341 func (g *genStreamer) se(t types.Type, n, rtype string, arrlen int64) string { 342 elmt := Element{ 343 Size: 1, 344 } 345 if arrlen > 0 { 346 elmt.Size = int32(arrlen) 347 elmt.ArrLen = int32(arrlen) 348 elmt.ArrDim = 1 349 elmt.MaxIdx[0] = elmt.ArrLen // FIXME(sbinet): handle n-dim arrays [n][m][u][v][w]T 350 } 351 352 ut := t.Underlying() 353 switch ut := ut.(type) { 354 case *types.Basic: 355 g.imps["go-hep.org/x/hep/groot/rbase"]++ 356 switch kind := ut.Kind(); kind { 357 case types.Bool: 358 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Bool %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 359 n, "", 360 rmeta.GoType2Cxx[ut.Name()], 361 rtype, 362 1*elmt.Size, 363 elmt.ArrLen, 364 elmt.ArrDim, 365 elmt.MaxIdx, 366 ) 367 case types.Uint8: 368 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint8 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 369 n, "", 370 rmeta.GoType2Cxx[ut.Name()], 371 rtype, 372 1*elmt.Size, 373 elmt.ArrLen, 374 elmt.ArrDim, 375 elmt.MaxIdx, 376 ) 377 case types.Uint16: 378 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint16 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 379 n, "", 380 rmeta.GoType2Cxx[ut.Name()], 381 rtype, 382 2*elmt.Size, 383 elmt.ArrLen, 384 elmt.ArrDim, 385 elmt.MaxIdx, 386 ) 387 case types.Uint32, types.Uint: 388 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint32 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 389 n, "", 390 rmeta.GoType2Cxx[ut.Name()], 391 rtype, 392 4*elmt.Size, 393 elmt.ArrLen, 394 elmt.ArrDim, 395 elmt.MaxIdx, 396 ) 397 case types.Uint64: 398 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Uint64 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 399 n, "", 400 rmeta.GoType2Cxx[ut.Name()], 401 rtype, 402 8*elmt.Size, 403 elmt.ArrLen, 404 elmt.ArrDim, 405 elmt.MaxIdx, 406 ) 407 case types.Int8: 408 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int8 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 409 n, "", 410 rmeta.GoType2Cxx[ut.Name()], 411 rtype, 412 1*elmt.Size, 413 elmt.ArrLen, 414 elmt.ArrDim, 415 elmt.MaxIdx, 416 ) 417 case types.Int16: 418 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int16 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 419 n, "", 420 rmeta.GoType2Cxx[ut.Name()], 421 rtype, 422 2*elmt.Size, 423 elmt.ArrLen, 424 elmt.ArrDim, 425 elmt.MaxIdx, 426 ) 427 case types.Int32, types.Int: 428 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int32 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 429 n, "", 430 rmeta.GoType2Cxx[ut.Name()], 431 rtype, 432 4*elmt.Size, 433 elmt.ArrLen, 434 elmt.ArrDim, 435 elmt.MaxIdx, 436 ) 437 case types.Int64: 438 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Int64 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 439 n, "", 440 rmeta.GoType2Cxx[ut.Name()], 441 rtype, 442 8*elmt.Size, 443 elmt.ArrLen, 444 elmt.ArrDim, 445 elmt.MaxIdx, 446 ) 447 case types.Float32: 448 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Float32 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 449 n, "", 450 rmeta.GoType2Cxx[ut.Name()], 451 rtype, 452 4*elmt.Size, 453 elmt.ArrLen, 454 elmt.ArrDim, 455 elmt.MaxIdx, 456 ) 457 case types.Float64: 458 return fmt.Sprintf("rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.Float64 %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()", 459 n, "", 460 rmeta.GoType2Cxx[ut.Name()], 461 rtype, 462 8*elmt.Size, 463 elmt.ArrLen, 464 elmt.ArrDim, 465 elmt.MaxIdx, 466 ) 467 case types.Complex64: 468 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 469 470 case types.Complex128: 471 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 472 473 case types.String: 474 return fmt.Sprintf("&rdict.StreamerString{rdict.Element{\nName: *rbase.NewNamed(%[1]q, %[2]q),\nType: rmeta.TString %[4]s,\nSize: %[5]d,\nEName:%[3]q,\nArrLen:%[6]d,\nArrDim:%[7]d,\nMaxIdx:%#[8]v,\n}.New()}", 475 n, "", 476 "TString", 477 rtype, 478 24*elmt.Size, 479 elmt.ArrLen, 480 elmt.ArrDim, 481 elmt.MaxIdx, 482 ) 483 } 484 case *types.Struct: 485 // FIXME(sbinet): implement. 486 // FIXME(sbinet): prevent recursion. 487 old := g.buf 488 g.buf = new(bytes.Buffer) 489 g.genStreamerType(t, n) 490 str := g.buf.String() 491 g.buf = old 492 return str 493 } 494 495 log.Printf("gen-streamer: unhandled type: %v (underlying %v)", t, ut) 496 return "" 497 } 498 499 func (g *genStreamer) genMarshalType(t types.Type, n string) { 500 ut := t.Underlying() 501 switch ut := ut.(type) { 502 case *types.Basic: 503 switch kind := ut.Kind(); kind { 504 case types.Bool: 505 g.wt(ut, n, "", "") 506 case types.Uint8: 507 g.wt(ut, n, "", "") 508 case types.Uint16: 509 g.wt(ut, n, "", "") 510 case types.Uint32: 511 g.wt(ut, n, "", "") 512 case types.Uint64: 513 g.wt(ut, n, "", "") 514 case types.Int8: 515 g.wt(ut, n, "", "") 516 case types.Int16: 517 g.wt(ut, n, "", "") 518 case types.Int32: 519 g.wt(ut, n, "", "") 520 case types.Int64: 521 g.wt(ut, n, "", "") 522 case types.Float32: 523 g.wt(ut, n, "", "") 524 case types.Float64: 525 g.wt(ut, n, "", "") 526 527 case types.Uint: 528 g.wt(ut, n, "", "") 529 case types.Int: 530 g.wt(ut, n, "", "") 531 532 case types.Complex64: 533 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 534 case types.Complex128: 535 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 536 537 case types.String: 538 g.wt(ut, n, "", "") 539 540 default: 541 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 542 } 543 544 case *types.Array: 545 switch ut.Elem().Underlying().(type) { 546 case *types.Basic: 547 g.wt(ut.Elem(), n, "Array", "[:]") 548 default: 549 g.printf("for i := range o.%s {\n", n) 550 g.wt(ut.Elem(), n+"[i]", "", "") 551 g.printf("}\n") 552 } 553 554 case *types.Slice: 555 g.wt(ut.Elem(), n, "Array", "") 556 557 case *types.Struct: 558 g.printf("w.WriteObject(&o.%s)\n", n) 559 560 default: 561 log.Fatalf("gen-marshal-type: unhandled type: %v (underlying: %v)\n", t, ut) 562 } 563 } 564 565 // Generate implements rdict.Generator 566 func (g *genStreamer) Format() ([]byte, error) { 567 buf := new(bytes.Buffer) 568 569 buf.WriteString(fmt.Sprintf(`// DO NOT EDIT; automatically generated by %[1]s 570 571 package %[2]s 572 573 import ( 574 `, 575 "root-gen-streamer", 576 g.pkg.Name(), 577 )) 578 579 // FIXME(sbinet): separate stdlib from 3rd-party imports. 580 581 for k := range g.imps { 582 fmt.Fprintf(buf, "%q\n", k) 583 } 584 fmt.Fprintf(buf, ")\n\n") 585 586 buf.Write(g.buf.Bytes()) 587 588 src, err := format.Source(buf.Bytes()) 589 if err != nil { 590 log.Printf("=== error ===\n%s\n", buf.Bytes()) 591 } 592 return src, err 593 } 594 595 var ( 596 _ Generator = (*genStreamer)(nil) 597 )