go-hep.org/x/hep@v0.40.0/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.TypeFor[int]().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 ft := range typ.Fields() { 158 n := ft.Name() // no `groot:"foo"` redirection. 159 g.genMarshalType(ft.Type(), n) 160 } 161 162 g.printf("\n\treturn w.SetHeader(hdr)\n}\n\n") 163 } 164 165 // func (g *genStreamer) genUnmarshal(t types.Type, typeName string) { 166 // g.printf(`// UnmarshalROOT implements rbytes.Unmarshaler 167 // func (o *%[1]s) UnmarshalROOT(r *rbytes.RBuffer) error { 168 // rs, err := rdict.RStreamer(r, o) 169 // if err != nil { 170 // return err 171 // } 172 // return rs.RStreamROOT(r) 173 // } 174 // `, 175 // typeName, 176 // ) 177 // } 178 179 func (g *genStreamer) genRVersioner(t types.Type, typeName string) { 180 g.printf("func (*%s) RVersion() int16 { return 1 }\n\n", typeName) 181 } 182 183 func (g *genStreamer) genStreamer(t types.Type, typeName string) { 184 g.printf(`func init() { 185 // Streamer for %[1]s. 186 rdict.StreamerInfos.Add(rdict.NewStreamerInfo(%[2]q, int(((*%[1]s)(nil)).RVersion()), []rbytes.StreamerElement{ 187 `, 188 typeName, 189 g.pkg.Path()+"."+typeName, 190 ) 191 192 typ := t.Underlying().(*types.Struct) 193 for i := range typ.NumFields() { 194 ft := typ.Field(i) 195 n := ft.Name() 196 if tag := typ.Tag(i); tag != "" { 197 nn := reflect.StructTag(tag).Get("groot") 198 if nn != "" { 199 n = nn 200 } 201 } 202 g.genStreamerType(ft.Type(), n) 203 } 204 205 g.printf("}))\n}\n\n") 206 } 207 208 func (g *genStreamer) genStreamerType(t types.Type, n string) { 209 ut := t.Underlying() 210 switch ut := ut.(type) { 211 case *types.Basic: 212 switch kind := ut.Kind(); kind { 213 case types.Bool: 214 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 215 case types.Uint8: 216 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 217 case types.Uint16: 218 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 219 case types.Uint32, types.Uint: 220 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 221 case types.Uint64: 222 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 223 case types.Int8: 224 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 225 case types.Int16: 226 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 227 case types.Int32, types.Int: 228 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 229 case types.Int64: 230 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 231 case types.Float32: 232 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 233 case types.Float64: 234 g.printf("&rdict.StreamerBasicType{StreamerElement: %s},\n", g.se(ut, n, "", 0)) 235 case types.Complex64: 236 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 237 238 case types.Complex128: 239 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 240 241 case types.String: 242 g.printf("%s,\n", g.se(ut, n, "", 0)) 243 244 default: 245 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 246 } 247 248 case *types.Array: 249 // FIXME(sbinet): collect+visit element type. 250 switch eut := ut.Elem().Underlying().(type) { 251 case *types.Basic: 252 switch kind := eut.Kind(); kind { 253 default: 254 g.printf( 255 "&rdict.StreamerBasicType{StreamerElement: %s},\n", 256 g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()), 257 ) 258 case types.String: 259 g.printf( 260 "%s,\n", 261 g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()), 262 ) 263 } 264 default: 265 g.printf( 266 "%s\n", 267 g.se(ut.Elem(), n, "+ rmeta.OffsetL", ut.Len()), 268 ) 269 } 270 case *types.Slice: 271 // FIXME(sbinet): collect+visit element type. 272 g.printf("rdict.NewStreamerSTL(%q, rmeta.STLvector, rmeta.%v),\n", n, gotype2RMeta(ut.Elem())) 273 274 case *types.Struct: 275 g.imps["go-hep.org/x/hep/groot/rbase"]++ 276 g.printf( 277 "&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", 278 n, "", 279 t.String(), g.gosizes.Sizeof(ut), 280 ) 281 282 default: 283 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 284 } 285 } 286 287 func (g *genStreamer) wt(t types.Type, n, meth, arr string) { 288 ut := t.Underlying() 289 switch ut := ut.(type) { 290 case *types.Basic: 291 switch kind := ut.Kind(); kind { 292 case types.Bool: 293 g.printf("w.Write%sBool(o.%s%s)\n", meth, n, arr) 294 case types.Uint8: 295 g.printf("w.Write%sU8(o.%s%s)\n", meth, n, arr) 296 case types.Uint16: 297 g.printf("w.Write%sU16(o.%s%s)\n", meth, n, arr) 298 case types.Uint32: 299 g.printf("w.Write%sU32(o.%s%s)\n", meth, n, arr) 300 case types.Uint64: 301 g.printf("w.Write%sU64(o.%s%s)\n", meth, n, arr) 302 case types.Int8: 303 g.printf("w.Write%sI8(o.%s%s)\n", meth, n, arr) 304 case types.Int16: 305 g.printf("w.Write%sI16(o.%s%s)\n", meth, n, arr) 306 case types.Int32: 307 g.printf("w.Write%sI32(o.%s%s)\n", meth, n, arr) 308 case types.Int64: 309 g.printf("w.Write%sI64(o.%s%s)\n", meth, n, arr) 310 case types.Float32: 311 g.printf("w.Write%sF32(o.%s%s)\n", meth, n, arr) 312 case types.Float64: 313 g.printf("w.Write%sF64(o.%s%s)\n", meth, n, arr) 314 315 case types.Uint: 316 g.printf("w.Write%sU64(uint64(o.%s%s))\n", meth, n, arr) 317 case types.Int: 318 g.printf("w.Write%sI64(int64(o.%s%s))\n", meth, n, arr) 319 320 case types.Complex64: 321 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 322 case types.Complex128: 323 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 324 325 case types.String: 326 g.printf("w.Write%sString(o.%s%s)\n", meth, n, arr) 327 328 default: 329 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 330 } 331 332 case *types.Struct: 333 g.printf("w.WriteObject(&o.%s)\n", n) 334 335 default: 336 log.Fatalf("unhandled marshal type: %v (underlying %v)", t, ut) 337 } 338 } 339 340 func (g *genStreamer) se(t types.Type, n, rtype string, arrlen int64) string { 341 elmt := Element{ 342 Size: 1, 343 } 344 if arrlen > 0 { 345 elmt.Size = int32(arrlen) 346 elmt.ArrLen = int32(arrlen) 347 elmt.ArrDim = 1 348 elmt.MaxIdx[0] = elmt.ArrLen // FIXME(sbinet): handle n-dim arrays [n][m][u][v][w]T 349 } 350 351 ut := t.Underlying() 352 switch ut := ut.(type) { 353 case *types.Basic: 354 g.imps["go-hep.org/x/hep/groot/rbase"]++ 355 switch kind := ut.Kind(); kind { 356 case types.Bool: 357 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()", 358 n, "", 359 rmeta.GoType2Cxx[ut.Name()], 360 rtype, 361 1*elmt.Size, 362 elmt.ArrLen, 363 elmt.ArrDim, 364 elmt.MaxIdx, 365 ) 366 case types.Uint8: 367 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()", 368 n, "", 369 rmeta.GoType2Cxx[ut.Name()], 370 rtype, 371 1*elmt.Size, 372 elmt.ArrLen, 373 elmt.ArrDim, 374 elmt.MaxIdx, 375 ) 376 case types.Uint16: 377 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()", 378 n, "", 379 rmeta.GoType2Cxx[ut.Name()], 380 rtype, 381 2*elmt.Size, 382 elmt.ArrLen, 383 elmt.ArrDim, 384 elmt.MaxIdx, 385 ) 386 case types.Uint32, types.Uint: 387 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()", 388 n, "", 389 rmeta.GoType2Cxx[ut.Name()], 390 rtype, 391 4*elmt.Size, 392 elmt.ArrLen, 393 elmt.ArrDim, 394 elmt.MaxIdx, 395 ) 396 case types.Uint64: 397 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()", 398 n, "", 399 rmeta.GoType2Cxx[ut.Name()], 400 rtype, 401 8*elmt.Size, 402 elmt.ArrLen, 403 elmt.ArrDim, 404 elmt.MaxIdx, 405 ) 406 case types.Int8: 407 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()", 408 n, "", 409 rmeta.GoType2Cxx[ut.Name()], 410 rtype, 411 1*elmt.Size, 412 elmt.ArrLen, 413 elmt.ArrDim, 414 elmt.MaxIdx, 415 ) 416 case types.Int16: 417 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()", 418 n, "", 419 rmeta.GoType2Cxx[ut.Name()], 420 rtype, 421 2*elmt.Size, 422 elmt.ArrLen, 423 elmt.ArrDim, 424 elmt.MaxIdx, 425 ) 426 case types.Int32, types.Int: 427 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()", 428 n, "", 429 rmeta.GoType2Cxx[ut.Name()], 430 rtype, 431 4*elmt.Size, 432 elmt.ArrLen, 433 elmt.ArrDim, 434 elmt.MaxIdx, 435 ) 436 case types.Int64: 437 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()", 438 n, "", 439 rmeta.GoType2Cxx[ut.Name()], 440 rtype, 441 8*elmt.Size, 442 elmt.ArrLen, 443 elmt.ArrDim, 444 elmt.MaxIdx, 445 ) 446 case types.Float32: 447 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()", 448 n, "", 449 rmeta.GoType2Cxx[ut.Name()], 450 rtype, 451 4*elmt.Size, 452 elmt.ArrLen, 453 elmt.ArrDim, 454 elmt.MaxIdx, 455 ) 456 case types.Float64: 457 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()", 458 n, "", 459 rmeta.GoType2Cxx[ut.Name()], 460 rtype, 461 8*elmt.Size, 462 elmt.ArrLen, 463 elmt.ArrDim, 464 elmt.MaxIdx, 465 ) 466 case types.Complex64: 467 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 468 469 case types.Complex128: 470 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 471 472 case types.String: 473 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()}", 474 n, "", 475 "TString", 476 rtype, 477 24*elmt.Size, 478 elmt.ArrLen, 479 elmt.ArrDim, 480 elmt.MaxIdx, 481 ) 482 } 483 case *types.Struct: 484 // FIXME(sbinet): implement. 485 // FIXME(sbinet): prevent recursion. 486 old := g.buf 487 g.buf = new(bytes.Buffer) 488 g.genStreamerType(t, n) 489 str := g.buf.String() 490 g.buf = old 491 return str 492 } 493 494 log.Printf("gen-streamer: unhandled type: %v (underlying %v)", t, ut) 495 return "" 496 } 497 498 func (g *genStreamer) genMarshalType(t types.Type, n string) { 499 ut := t.Underlying() 500 switch ut := ut.(type) { 501 case *types.Basic: 502 switch kind := ut.Kind(); kind { 503 case types.Bool: 504 g.wt(ut, n, "", "") 505 case types.Uint8: 506 g.wt(ut, n, "", "") 507 case types.Uint16: 508 g.wt(ut, n, "", "") 509 case types.Uint32: 510 g.wt(ut, n, "", "") 511 case types.Uint64: 512 g.wt(ut, n, "", "") 513 case types.Int8: 514 g.wt(ut, n, "", "") 515 case types.Int16: 516 g.wt(ut, n, "", "") 517 case types.Int32: 518 g.wt(ut, n, "", "") 519 case types.Int64: 520 g.wt(ut, n, "", "") 521 case types.Float32: 522 g.wt(ut, n, "", "") 523 case types.Float64: 524 g.wt(ut, n, "", "") 525 526 case types.Uint: 527 g.wt(ut, n, "", "") 528 case types.Int: 529 g.wt(ut, n, "", "") 530 531 case types.Complex64: 532 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 533 case types.Complex128: 534 log.Fatalf("unhandled type: %v (underlying %v)\n", t, ut) // FIXME(sbinet) 535 536 case types.String: 537 g.wt(ut, n, "", "") 538 539 default: 540 log.Fatalf("unhandled type: %v (underlying: %v)\n", t, ut) 541 } 542 543 case *types.Array: 544 switch ut.Elem().Underlying().(type) { 545 case *types.Basic: 546 g.wt(ut.Elem(), n, "Array", "[:]") 547 default: 548 g.printf("for i := range o.%s {\n", n) 549 g.wt(ut.Elem(), n+"[i]", "", "") 550 g.printf("}\n") 551 } 552 553 case *types.Slice: 554 g.wt(ut.Elem(), n, "Array", "") 555 556 case *types.Struct: 557 g.printf("w.WriteObject(&o.%s)\n", n) 558 559 default: 560 log.Fatalf("gen-marshal-type: unhandled type: %v (underlying: %v)\n", t, ut) 561 } 562 } 563 564 // Generate implements rdict.Generator 565 func (g *genStreamer) Format() ([]byte, error) { 566 buf := new(bytes.Buffer) 567 568 buf.WriteString(fmt.Sprintf(`// DO NOT EDIT; automatically generated by %[1]s 569 570 package %[2]s 571 572 import ( 573 `, 574 "root-gen-streamer", 575 g.pkg.Name(), 576 )) 577 578 // FIXME(sbinet): separate stdlib from 3rd-party imports. 579 580 for k := range g.imps { 581 fmt.Fprintf(buf, "%q\n", k) 582 } 583 fmt.Fprintf(buf, ")\n\n") 584 585 buf.Write(g.buf.Bytes()) 586 587 src, err := format.Source(buf.Bytes()) 588 if err != nil { 589 log.Printf("=== error ===\n%s\n", buf.Bytes()) 590 } 591 return src, err 592 } 593 594 var ( 595 _ Generator = (*genStreamer)(nil) 596 )