github.com/neugram/ng@v0.0.0-20180309130942-d472ff93d872/gengo/gengo.go (about) 1 // Copyright 2017 The Neugram 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 gengo implements a backend for the Neugram parser and 6 // typechecker that generates a Go package. 7 package gengo 8 9 import ( 10 "bytes" 11 "fmt" 12 goformat "go/format" 13 "path" 14 "path/filepath" 15 "sort" 16 "strings" 17 "unicode" 18 "unicode/utf8" 19 20 "neugram.io/ng/format" 21 "neugram.io/ng/syntax" 22 "neugram.io/ng/syntax/expr" 23 "neugram.io/ng/syntax/stmt" 24 "neugram.io/ng/syntax/tipe" 25 "neugram.io/ng/syntax/token" 26 "neugram.io/ng/typecheck" 27 ) 28 29 func GenGo(filename, outGoPkgName string) (result []byte, err error) { 30 p := &printer{ 31 buf: new(bytes.Buffer), 32 c: typecheck.New(filepath.Base(filename)), // TODO: extract a pkg name 33 imports: make(map[*tipe.Package]string), 34 eliders: make(map[tipe.Type]string), 35 } 36 37 abspath, err := filepath.Abs(filename) 38 if err != nil { 39 return nil, err 40 } 41 42 p.pkg, err = p.c.Check(abspath) 43 if err != nil { 44 return nil, err 45 } 46 47 if outGoPkgName == "" { 48 outGoPkgName = "gengo_" + strings.TrimSuffix(filepath.Base(filename), ".ng") 49 } 50 p.printf(`// generated by ng, do not edit 51 52 package %s 53 54 `, outGoPkgName) 55 56 usesShell := false 57 builtins := make(map[string]bool) 58 importPaths := []string{} 59 preFn := func(c *syntax.Cursor) bool { 60 switch node := c.Node.(type) { 61 case *stmt.Import: 62 importPaths = append(importPaths, node.Path) 63 case *expr.Ident: 64 // TODO: look up the typecheck.Obj for builtins 65 switch node.Name { 66 case "printf": 67 builtins["printf"] = true 68 case "print": 69 builtins["print"] = true 70 case "errorf": 71 builtins["errorf"] = true 72 } 73 case *expr.ShellList: 74 usesShell = true 75 } 76 return true 77 } 78 syntax.Walk(p.pkg.Syntax, preFn, nil) 79 80 // Lift imports to the top-level. 81 importSet := make(map[string]bool) 82 for _, imp := range importPaths { 83 importSet[imp] = true 84 } 85 // Name. 86 namedImports := make(map[string]string) // name -> path 87 for imp := range importSet { 88 name := "gengoimp_" + path.Base(imp) 89 i := 0 90 for namedImports[name] != "" { 91 i++ 92 name = fmt.Sprintf("gengoimp_%s_%d", path.Base(imp), i) 93 } 94 namedImports[name] = imp 95 p.imports[p.c.Pkg(imp).Type] = name 96 } 97 98 p.printf("import (") 99 p.indent++ 100 101 if builtins["printf"] || builtins["print"] || builtins["errorf"] { 102 p.newline() 103 p.printf(`"fmt"`) 104 } 105 if usesShell { 106 p.newline() 107 p.printf(`"fmt"`) 108 p.newline() 109 p.printf(`"os"`) 110 p.newline() 111 p.printf(`"reflect"`) 112 p.newline() 113 p.printf(`"neugram.io/ng/eval/environ"`) 114 p.newline() 115 p.printf(`"neugram.io/ng/eval/shell"`) 116 p.newline() 117 p.printf(`"neugram.io/ng/syntax/expr"`) 118 p.newline() 119 p.printf(`"neugram.io/ng/syntax/src"`) 120 p.newline() 121 p.printf(`"neugram.io/ng/syntax/token"`) 122 } 123 124 // Stable output is ensured by gofmt's sorting later. 125 for name, imp := range namedImports { 126 p.newline() 127 p.printf("%s %q", name, imp) 128 } 129 130 p.indent-- 131 p.newline() 132 p.print(")") 133 p.newline() 134 p.newline() 135 136 if outGoPkgName == "main" { 137 p.printf("func main() {}") 138 p.newline() 139 p.newline() 140 } 141 142 // Lift package-level declarations to the top-level. 143 for _, obj := range p.pkg.Globals { 144 switch obj.Kind { 145 case typecheck.ObjType: 146 n := obj.Type.(*tipe.Named) 147 if len(n.Methods) > 0 { 148 continue // methodiks are hoisted elsewhere 149 } 150 p.printf("type %s ", obj.Name) 151 p.tipe(n.Type) 152 case typecheck.ObjVar: 153 p.printf("var %s ", obj.Name) 154 p.tipe(obj.Type) 155 case typecheck.ObjConst: 156 p.printf("const %s = %s", obj.Name, obj.Decl) 157 } 158 p.newline() 159 p.newline() 160 } 161 162 // Lift methodik declarations to the top-level. 163 methodiks := make(map[string][]*stmt.MethodikDecl) 164 preFn = func(c *syntax.Cursor) bool { 165 switch node := c.Node.(type) { 166 case *stmt.MethodikDecl: 167 methodiks[node.Name] = append(methodiks[node.Name], node) 168 } 169 return true 170 } 171 syntax.Walk(p.pkg.Syntax, preFn, nil) 172 methodiksFlat := make(map[string]*stmt.MethodikDecl) 173 for name, ms := range methodiks { 174 methodiksFlat[name] = ms[0] 175 if len(ms) == 1 { 176 continue 177 } 178 for i, m := range ms[1:] { 179 var newName string 180 for { 181 newName = fmt.Sprintf("%s_gengo%d", name, i) 182 if _, exists := methodiks[newName]; !exists { 183 break 184 } 185 i++ 186 } 187 methodiksFlat[newName] = m 188 m.Type.Name = newName 189 } 190 } 191 var methodikNames []string 192 for name := range methodiksFlat { 193 methodikNames = append(methodikNames, name) 194 } 195 sort.Strings(methodikNames) 196 for _, name := range methodikNames { 197 m := methodiksFlat[name] 198 p.printf("// methodik %s", m.Name) 199 p.newline() 200 p.printf("type %s %s", m.Name, format.Type(m.Type.Type)) 201 p.newline() 202 p.newline() 203 for _, method := range m.Methods { 204 p.funcLiteral(method, m.Name) 205 p.newline() 206 p.newline() 207 } 208 } 209 210 p.print("func init() {") 211 p.indent++ 212 for _, s := range p.pkg.Syntax.Stmts { 213 switch s.(type) { 214 case *stmt.TypeDecl: 215 // handled above 216 continue 217 } 218 219 p.newline() 220 p.stmt(s) 221 222 if s, isAssign := s.(*stmt.Assign); isAssign { 223 // TODO: look to see if typecheck object is used, 224 // only emit this if it isn't. 225 if s.Decl { 226 for _, e := range s.Left { 227 if ident, isIdent := e.(*expr.Ident); isIdent && ident.Name == "_" { 228 continue 229 } 230 p.newline() 231 p.print("_ = ") 232 p.expr(e) 233 } 234 } 235 } 236 } 237 p.indent-- 238 p.newline() 239 p.print("}") 240 241 p.printBuiltins(builtins) 242 p.printEliders() 243 if usesShell { 244 p.printShell() 245 } 246 247 res, err := goformat.Source(p.buf.Bytes()) 248 if err != nil { 249 lines := new(bytes.Buffer) 250 for i, line := range strings.Split(p.buf.String(), "\n") { 251 fmt.Fprintf(lines, "%3d: %s\n", i+1, line) 252 } 253 return nil, fmt.Errorf("gengo: bad generated source: %v\n%s", err, lines.String()) 254 } 255 256 return res, nil 257 } 258 259 type printer struct { 260 buf *bytes.Buffer 261 indent int 262 263 imports map[*tipe.Package]string // import package -> name 264 c *typecheck.Checker 265 pkg *typecheck.Package 266 eliders map[tipe.Type]string 267 268 underlying bool // always print underlying type 269 typeCur *tipe.Named 270 typePlugins map[*tipe.Named]string // plugin pkg path 271 typePluginsUsed map[*tipe.Named]bool 272 } 273 274 func (p *printer) printShell() { 275 p.newline() 276 p.newline() 277 p.printf(`var _ = src.Pos{} // used in some expr.Shell prints`) 278 p.newline() 279 p.printf(`var _ = token.Token(0)`) 280 p.newline() 281 p.printf(`var shellState = &shell.State{ 282 Env: environ.NewFrom(os.Environ()), 283 Alias: environ.New(), 284 }`) 285 286 p.newline() 287 p.newline() 288 p.printf(`func init() { 289 wd, err := os.Getwd() 290 if err == nil { 291 shellState.Env.Set("PWD", wd) 292 } 293 }`) 294 295 p.newline() 296 p.newline() 297 p.printf(`func gengo_shell(e *expr.Shell, p gengo_shell_params) (string, error) { 298 str, err := shell.Run(shellState, p, e) 299 return str, err 300 } 301 302 func gengo_shell_elide(e *expr.Shell, p gengo_shell_params) string { 303 str, err := gengo_shell(e, p) 304 if err != nil { 305 panic(err) 306 } 307 return str 308 } 309 310 type gengo_shell_params map[string]reflect.Value 311 312 func (p gengo_shell_params) Get(name string) string { 313 if v, found := p[name]; found { 314 vi := v.Interface() 315 if s, ok := vi.(string); ok { 316 return s 317 } 318 return fmt.Sprint(vi) 319 } 320 return shellState.Env.Get(name) 321 } 322 323 func (p gengo_shell_params) Set(name, value string) { 324 v, found := p[name] 325 if !found { 326 v = reflect.ValueOf(&value).Elem() 327 p[name] = v 328 } 329 if v.Kind() == reflect.String { 330 v.SetString(value) 331 } else { 332 fmt.Sscan(value, v) 333 } 334 } 335 336 func init() { shell.Init() } 337 `) 338 } 339 340 func (p *printer) printBuiltins(builtins map[string]bool) { 341 if builtins["print"] { 342 p.newline() 343 p.newline() 344 p.print(`func print(args ...interface{}) { 345 for _, arg := range args { 346 fmt.Printf("%v", arg) 347 } 348 fmt.Print("\n") 349 }`) 350 } 351 352 if builtins["printf"] { 353 p.newline() 354 p.newline() 355 p.print("func printf(f string, args ...interface{}) { fmt.Printf(f, args...) }") 356 } 357 358 if builtins["errorf"] { 359 p.newline() 360 p.newline() 361 p.print("func errorf(f string, args ...interface{}) error { return fmt.Errorf(f, args...) }") 362 } 363 } 364 365 func (p *printer) printEliders() { 366 for t, name := range p.eliders { 367 p.newline() 368 p.newline() 369 if typecheck.IsError(t) { 370 p.printf("func %s(err error) {", name) 371 p.indent++ 372 p.newline() 373 p.printf("if err != nil { panic(err) }") 374 p.indent++ 375 p.newline() 376 p.printf("}") 377 continue 378 } 379 380 p.printf("func %s(", name) 381 elems := t.(*tipe.Tuple).Elems 382 for i, elem := range elems { 383 if i == len(elems)-1 { 384 p.printf("err error") 385 continue 386 } 387 p.printf("arg%d ", i) 388 p.tipe(elem) 389 p.printf(", ") 390 } 391 p.printf(") (") 392 for i, elem := range elems[:len(elems)-1] { 393 if i > 0 { 394 p.printf(", ") 395 } 396 p.tipe(elem) 397 } 398 p.printf(") {") 399 p.indent++ 400 p.newline() 401 p.printf("if err != nil { panic(err) }") 402 p.newline() 403 p.printf("return ") 404 for i := range elems[:len(elems)-1] { 405 if i > 0 { 406 p.printf(", ") 407 } 408 p.printf("arg%d", i) 409 } 410 p.indent++ 411 p.newline() 412 p.printf("}") 413 } 414 } 415 416 func (p *printer) printf(format string, args ...interface{}) { 417 fmt.Fprintf(p.buf, format, args...) 418 } 419 420 func (p *printer) print(str string) { 421 p.buf.WriteString(str) 422 } 423 424 func (p *printer) newline() { 425 p.buf.WriteByte('\n') 426 for i := 0; i < p.indent; i++ { 427 p.buf.WriteByte('\t') 428 } 429 } 430 431 func (p *printer) expr(e expr.Expr) { 432 switch e := e.(type) { 433 case *expr.BasicLiteral: 434 if str, isStr := e.Value.(string); isStr { 435 p.printf("%q", str) 436 } else { 437 p.printf("%v", e.Value) 438 } 439 case *expr.Binary: 440 p.expr(e.Left) 441 p.printf(" %s ", e.Op) 442 p.expr(e.Right) 443 case *expr.Call: 444 if e.ElideError { 445 fnName := p.elider(p.c.Type(e)) 446 p.printf("%s(", fnName) 447 } 448 p.expr(e.Func) 449 p.print("(") 450 for i, arg := range e.Args { 451 if i != 0 { 452 p.print(", ") 453 } 454 p.expr(arg) 455 } 456 if e.Ellipsis { 457 p.print("...") 458 } 459 p.print(")") 460 if e.ElideError { 461 p.print(")") 462 } 463 case *expr.CompLiteral: 464 p.tipe(e.Type) 465 p.print("{") 466 if len(e.Keys) > 0 { 467 p.indent++ 468 for i, key := range e.Keys { 469 p.newline() 470 p.expr(key) 471 p.print(": ") 472 p.expr(e.Values[i]) 473 p.print(",") 474 } 475 p.indent-- 476 p.newline() 477 } else if len(e.Values) > 0 { 478 for i, elem := range e.Values { 479 if i > 0 { 480 p.print(", ") 481 } 482 p.expr(elem) 483 } 484 } 485 p.print("}") 486 case *expr.FuncLiteral: 487 if e.Name != "" { 488 gobj := p.pkg.GlobalNames[e.Name] 489 if gobj != nil && gobj.Decl == e { 490 p.printf("%s = ", e.Name) 491 } else { 492 p.printf("%s := ", e.Name) 493 } 494 } 495 p.funcLiteral(e, "") 496 case *expr.Ident: 497 if pkgType, isPkg := p.c.Type(e).(*tipe.Package); isPkg { 498 p.print(p.imports[pkgType]) 499 } else { 500 p.print(e.Name) 501 } 502 case *expr.Index: 503 p.expr(e.Left) 504 p.print("[") 505 for i, index := range e.Indicies { 506 if i > 0 { 507 p.print(", ") 508 } 509 p.expr(index) 510 } 511 p.print("]") 512 case *expr.MapLiteral: 513 p.tipe(e.Type) 514 p.print("{") 515 p.indent++ 516 for i, key := range e.Keys { 517 p.newline() 518 p.expr(key) 519 p.print(": ") 520 p.expr(e.Values[i]) 521 p.print(",") 522 } 523 p.indent-- 524 p.newline() 525 p.print("}") 526 case *expr.Selector: 527 p.expr(e.Left) 528 p.print(".") 529 p.expr(e.Right) 530 case *expr.Slice: 531 if e.Low != nil { 532 p.expr(e.Low) 533 } 534 p.buf.WriteString(":") 535 if e.High != nil { 536 p.expr(e.High) 537 } 538 if e.Max != nil { 539 p.buf.WriteString(":") 540 p.expr(e.Max) 541 } 542 case *expr.Shell: 543 if e.ElideError { 544 p.printf("gengo_shell_elide(%s, gengo_shell_params{", format.Debug(e)) 545 } else { 546 p.printf("gengo_shell(%s, gengo_shell_params{", format.Debug(e)) 547 } 548 if len(e.FreeVars) > 0 { 549 p.indent++ 550 for _, name := range e.FreeVars { 551 p.newline() 552 p.printf("%q: reflect.ValueOf(&%s).Elem(),", name, name) 553 } 554 p.indent-- 555 p.newline() 556 } 557 p.printf("})") 558 case *expr.ArrayLiteral: 559 p.tipe(e.Type) 560 p.print("{") 561 switch len(e.Keys) { 562 case 0: 563 for i, elem := range e.Values { 564 if i > 0 { 565 p.print(", ") 566 } 567 p.expr(elem) 568 } 569 default: 570 for i, elem := range e.Values { 571 if i > 0 { 572 p.print(", ") 573 } 574 p.expr(e.Keys[i]) 575 p.print(": ") 576 p.expr(elem) 577 } 578 } 579 p.print("}") 580 case *expr.SliceLiteral: 581 p.tipe(e.Type) 582 p.print("{") 583 switch len(e.Keys) { 584 case 0: 585 for i, elem := range e.Values { 586 if i > 0 { 587 p.print(", ") 588 } 589 p.expr(elem) 590 } 591 default: 592 for i, elem := range e.Values { 593 if i > 0 { 594 p.print(", ") 595 } 596 p.expr(e.Keys[i]) 597 p.print(": ") 598 p.expr(elem) 599 } 600 } 601 p.print("}") 602 case *expr.Type: 603 p.tipe(e.Type) 604 case *expr.TypeAssert: 605 p.expr(e.Left) 606 p.print(".(") 607 if e.Type == nil { 608 p.print("type") 609 } else { 610 p.tipe(e.Type) 611 } 612 p.print(")") 613 case *expr.Unary: 614 p.print(e.Op.String()) 615 p.expr(e.Expr) 616 if e.Op == token.LeftParen { 617 p.print(")") 618 } 619 } 620 } 621 622 func (p *printer) stmt(s stmt.Stmt) { 623 switch s := s.(type) { 624 case *stmt.ConstSet: 625 p.print("const (") 626 p.indent++ 627 for _, v := range s.Consts { 628 p.newline() 629 p.stmtConst(v) 630 } 631 p.indent-- 632 p.newline() 633 p.print(")") 634 case *stmt.Const: 635 p.print("const ") 636 p.stmtConst(s) 637 case *stmt.VarSet: 638 p.print("var (") 639 p.indent++ 640 for _, v := range s.Vars { 641 p.newline() 642 p.stmtVar(v) 643 } 644 p.indent-- 645 p.newline() 646 p.print(")") 647 case *stmt.Var: 648 p.print("var ") 649 p.stmtVar(s) 650 case *stmt.Assign: 651 for i, e := range s.Left { 652 if i != 0 { 653 p.print(", ") 654 } 655 p.expr(e) 656 } 657 // TODO: A, b := ... 658 ident, _ := s.Left[0].(*expr.Ident) 659 var obj *typecheck.Obj 660 if ident != nil { 661 obj = p.c.Ident(ident) 662 } 663 if !s.Decl || (obj != nil && p.pkg.GlobalNames[obj.Name] == obj) { 664 p.print(" = ") 665 } else { 666 p.print(" := ") 667 } 668 for i, e := range s.Right { 669 if i != 0 { 670 p.print(", ") 671 } 672 p.expr(e) 673 } 674 case *stmt.Block: 675 p.print("{") 676 p.indent++ 677 for _, s := range s.Stmts { 678 p.newline() 679 p.stmt(s) 680 } 681 p.indent-- 682 p.newline() 683 p.print("}") 684 case *stmt.For: 685 p.print("for ") 686 if s.Init != nil { 687 p.stmt(s.Init) 688 p.print("; ") 689 } 690 if s.Cond != nil { 691 p.expr(s.Cond) 692 p.print("; ") 693 } 694 if s.Post != nil { 695 p.stmt(s.Post) 696 } 697 p.stmt(s.Body) 698 case *stmt.Go: 699 p.print("go ") 700 p.expr(s.Call) 701 case *stmt.If: 702 p.print("if ") 703 if s.Init != nil { 704 p.stmt(s.Init) 705 p.print("; ") 706 } 707 p.expr(s.Cond) 708 p.print(" ") 709 p.stmt(s.Body) 710 if s.Else != nil { 711 p.print(" else ") 712 p.stmt(s.Else) 713 } 714 case *stmt.ImportSet: 715 // lifted to top-level earlier 716 case *stmt.Import: 717 // lifted to top-level earlier 718 case *stmt.Range: 719 p.print("for ") 720 if s.Key != nil { 721 p.expr(s.Key) 722 } 723 if s.Val != nil { 724 p.print(", ") 725 p.expr(s.Val) 726 } 727 if s.Decl { 728 p.print(":") 729 } 730 if s.Key != nil || s.Val != nil { 731 p.print("= ") 732 } 733 p.print("range ") 734 p.expr(s.Expr) 735 p.stmt(s.Body) 736 case *stmt.Defer: 737 p.print("defer ") 738 p.expr(s.Expr) 739 case *stmt.Return: 740 p.print("return") 741 for i, e := range s.Exprs { 742 if i == 0 { 743 p.print(" ") 744 } else { 745 p.print(", ") 746 } 747 p.expr(e) 748 } 749 case *stmt.Simple: 750 // In Neugram it is valid to evaluate and not use an expression. 751 // (Because evaluating it has the standard side effect of 752 // printing its result.) 753 if p.isPure(s.Expr) { 754 p.print("_ = ") 755 } 756 p.expr(s.Expr) 757 case *stmt.Send: 758 p.expr(s.Chan) 759 p.print(" <- ") 760 p.expr(s.Value) 761 case *stmt.TypeDecl: 762 p.printf("type %s ", s.Name) 763 p.tipe(s.Type.Type) 764 case *stmt.TypeDeclSet: 765 p.print("type (") 766 p.indent++ 767 for _, t := range s.TypeDecls { 768 p.newline() 769 p.printf("%s ", t.Name) 770 p.tipe(t.Type.Type) 771 } 772 p.indent-- 773 p.newline() 774 p.print(")") 775 case *stmt.MethodikDecl: 776 // lifted to top-level earlier 777 case *stmt.Labeled: 778 p.indent-- 779 p.newline() 780 p.printf("%s:", s.Label) 781 p.indent++ 782 p.newline() 783 p.stmt(s.Stmt) 784 case *stmt.Branch: 785 p.printf("%s", s.Type) 786 if s.Label != "" { 787 p.printf(" %s", s.Label) 788 } 789 case *stmt.Switch: 790 p.print("switch ") 791 if s.Init != nil { 792 p.stmt(s.Init) 793 p.print("; ") 794 } 795 if s.Cond != nil { 796 p.expr(s.Cond) 797 } 798 p.print(" {") 799 800 for _, c := range s.Cases { 801 p.newline() 802 if c.Default { 803 p.print("default:") 804 } else { 805 p.print("case ") 806 for i, e := range c.Conds { 807 if i > 0 { 808 p.print(", ") 809 } 810 p.expr(e) 811 } 812 p.print(":") 813 } 814 p.indent++ 815 for _, s := range c.Body.Stmts { 816 p.newline() 817 p.stmt(s) 818 } 819 p.indent-- 820 } 821 822 p.newline() 823 p.print("}") 824 825 case *stmt.TypeSwitch: 826 p.print("switch ") 827 if s.Init != nil { 828 p.stmt(s.Init) 829 p.print("; ") 830 } 831 p.stmt(s.Assign) 832 p.print(" {") 833 834 for _, c := range s.Cases { 835 p.newline() 836 if c.Default { 837 p.print("default:") 838 } else { 839 p.print("case ") 840 for i, t := range c.Types { 841 if i > 0 { 842 p.print(", ") 843 } 844 p.tipe(t) 845 } 846 p.print(":") 847 } 848 p.indent++ 849 for _, s := range c.Body.Stmts { 850 p.newline() 851 p.stmt(s) 852 } 853 p.indent-- 854 } 855 856 p.newline() 857 p.print("}") 858 case *stmt.Select: 859 p.print("select {") 860 for _, c := range s.Cases { 861 p.newline() 862 if c.Default { 863 p.print("default:") 864 } else { 865 p.print("case ") 866 p.stmt(c.Stmt) 867 p.print(":") 868 } 869 p.indent++ 870 for _, s := range c.Body.Stmts { 871 p.newline() 872 p.stmt(s) 873 } 874 p.indent-- 875 } 876 p.newline() 877 p.print("}") 878 } 879 } 880 881 func (p *printer) isPure(e expr.Expr) bool { 882 switch e := e.(type) { 883 case *expr.Binary, *expr.Unary, *expr.Selector, *expr.Slice, *expr.CompLiteral, *expr.MapLiteral, *expr.ArrayLiteral, *expr.SliceLiteral, *expr.TableLiteral, *expr.Ident: 884 return true 885 case *expr.FuncLiteral: 886 return e.Name == "" 887 case *expr.Call: 888 t := p.c.Type(e.Func) 889 switch t { 890 case tipe.ComplexFunc, tipe.Imag, tipe.Real, tipe.New: 891 return true 892 } 893 return false 894 default: 895 return false 896 } 897 } 898 899 func (p *printer) stmtConst(s *stmt.Const) { 900 for i, n := range s.NameList { 901 if i != 0 { 902 p.print(", ") 903 } 904 p.print(n) 905 } 906 if s.Type != nil { 907 p.print(" ") 908 p.tipe(s.Type) 909 } 910 if len(s.Values) == 0 { 911 return 912 } 913 p.print(" = ") 914 for i, e := range s.Values { 915 if i != 0 { 916 p.print(", ") 917 } 918 p.expr(e) 919 } 920 } 921 922 func (p *printer) stmtVar(s *stmt.Var) { 923 for i, n := range s.NameList { 924 if i != 0 { 925 p.print(", ") 926 } 927 p.print(n) 928 } 929 if s.Type != nil { 930 p.print(" ") 931 p.tipe(s.Type) 932 } 933 if len(s.Values) == 0 { 934 return 935 } 936 p.print(" = ") 937 for i, e := range s.Values { 938 if i != 0 { 939 p.print(", ") 940 } 941 p.expr(e) 942 } 943 } 944 945 // TODO there is a huge amount of overlap here with the format package. 946 // deduplicate somehow. 947 func (p *printer) tipe(t tipe.Type) { 948 switch t := t.(type) { 949 case tipe.Basic: 950 p.print(string(t)) 951 case *tipe.Struct: 952 if len(t.Fields) == 0 { 953 p.print("struct{}") 954 return 955 } 956 p.print("struct {") 957 p.indent++ 958 maxlen := 0 959 for _, sf := range t.Fields { 960 if len(sf.Name) > maxlen { 961 maxlen = len(sf.Name) 962 } 963 } 964 for _, sf := range t.Fields { 965 p.newline() 966 name := sf.Name 967 if name == "" { 968 name = "*ERROR*No*Name*" 969 } 970 if !sf.Embedded { 971 p.print(name) 972 for i := len(name); i <= maxlen; i++ { 973 p.print(" ") 974 } 975 } 976 p.tipe(sf.Type) 977 if sf.Tag != "" { 978 p.printf(" %q", sf.Tag) 979 } 980 } 981 p.indent-- 982 p.newline() 983 p.print("}") 984 case *tipe.Named: 985 if t.PkgPath != "" && t.PkgPath != p.pkg.Path { 986 pkg := p.c.Pkg(t.PkgPath) 987 p.print(p.imports[pkg.Type]) 988 p.print(".") 989 p.print(t.Name) 990 } else if p.underlying && t.Name != "error" { 991 if t == p.typeCur { 992 p.print(t.Name) 993 } else if pkgpath := p.typePlugins[t]; pkgpath != "" { 994 // This type has methods and previously 995 // declared in a plugin. Use it. 996 p.typePluginsUsed[t] = true 997 p.print(path.Base(pkgpath)) 998 p.print(".") 999 p.print(t.Name) 1000 } else { 1001 p.tipe(tipe.Underlying(t)) 1002 } 1003 } else { 1004 p.print(t.Name) 1005 } 1006 case *tipe.Pointer: 1007 p.print("*") 1008 p.tipe(t.Elem) 1009 case *tipe.Unresolved: 1010 if t.Package != "" { 1011 p.print(t.Package) 1012 p.print(".") 1013 } 1014 p.print(t.Name) 1015 case *tipe.Array: 1016 // Do not print the ellipsis as we may be printing 1017 // a variable declaration for a global without the 1018 // initializer. 1019 p.printf("[%d]", t.Len) 1020 p.tipe(t.Elem) 1021 case *tipe.Slice: 1022 p.print("[]") 1023 p.tipe(t.Elem) 1024 case *tipe.Interface: 1025 if len(t.Methods) == 0 { 1026 p.print("interface{}") 1027 return 1028 } 1029 p.print("interface {") 1030 p.indent++ 1031 names := make([]string, 0, len(t.Methods)) 1032 for name := range t.Methods { 1033 names = append(names, name) 1034 } 1035 sort.Strings(names) 1036 for _, name := range names { 1037 p.newline() 1038 p.print(name) 1039 p.tipeFuncSig(t.Methods[name]) 1040 } 1041 p.indent-- 1042 p.newline() 1043 p.print("}") 1044 case *tipe.Map: 1045 p.print("map[") 1046 p.tipe(t.Key) 1047 p.print("]") 1048 p.tipe(t.Value) 1049 case *tipe.Chan: 1050 if t.Direction == tipe.ChanRecv { 1051 p.print("<-") 1052 } 1053 p.print("chan") 1054 if t.Direction == tipe.ChanSend { 1055 p.print("<-") 1056 } 1057 p.print(" ") 1058 p.tipe(t.Elem) 1059 case *tipe.Func: 1060 p.print("func") 1061 p.tipeFuncSig(t) 1062 case *tipe.Alias: 1063 p.print(t.Name) 1064 case *tipe.Tuple: 1065 p.print("(") 1066 for i, elt := range t.Elems { 1067 if i > 0 { 1068 p.print(", ") 1069 } 1070 p.tipe(elt) 1071 } 1072 p.print(")") 1073 case *tipe.Ellipsis: 1074 p.print("...") 1075 p.tipe(t.Elem) 1076 default: 1077 panic(fmt.Sprintf("unknown type: %T", t)) 1078 } 1079 } 1080 1081 func (p *printer) tipeFuncSig(t *tipe.Func) { 1082 p.print("(") 1083 if t.Params != nil { 1084 for i, elem := range t.Params.Elems { 1085 if i > 0 { 1086 p.print(", ") 1087 } 1088 p.tipe(elem) 1089 } 1090 } 1091 p.print(")") 1092 if t.Results != nil && len(t.Results.Elems) > 0 { 1093 p.print(" ") 1094 if len(t.Results.Elems) > 1 { 1095 p.print("(") 1096 } 1097 for i, elem := range t.Results.Elems { 1098 if i > 0 { 1099 p.print(", ") 1100 } 1101 p.tipe(elem) 1102 } 1103 if len(t.Results.Elems) > 1 { 1104 p.print(")") 1105 } 1106 } 1107 } 1108 1109 func (p *printer) funcLiteral(e *expr.FuncLiteral, recvTypeName string) { 1110 if recvTypeName != "" { 1111 ptr := "" 1112 if e.PointerReceiver { 1113 ptr = "*" 1114 } 1115 p.printf("func (%s %s%s) %s(", e.ReceiverName, ptr, recvTypeName, e.Name) 1116 } else { 1117 p.print("func(") 1118 } 1119 for i, name := range e.ParamNames { 1120 if i != 0 { 1121 p.print(", ") 1122 } 1123 p.print(name) 1124 p.print(" ") 1125 p.tipe(e.Type.Params.Elems[i]) 1126 } 1127 p.print(") ") 1128 if len(e.ResultNames) != 0 { 1129 p.print("(") 1130 for i, name := range e.ResultNames { 1131 if i != 0 { 1132 p.print(", ") 1133 } 1134 p.print(name) 1135 p.print(" ") 1136 p.tipe(e.Type.Results.Elems[i]) 1137 } 1138 p.print(")") 1139 } 1140 if e.Body != nil { 1141 p.print(" ") 1142 p.stmt(e.Body.(*stmt.Block)) 1143 } 1144 } 1145 1146 func (p *printer) elider(t tipe.Type) string { 1147 name := p.eliders[t] 1148 if name == "" { 1149 name = fmt.Sprintf("gengo_elider%d", len(p.eliders)) 1150 p.eliders[t] = name 1151 } 1152 return name 1153 } 1154 1155 func isExported(name string) bool { 1156 ch, _ := utf8.DecodeRuneInString(name) 1157 return unicode.IsUpper(ch) 1158 } 1159 1160 func GenNamedType(t *tipe.Named, methods []*expr.FuncLiteral, pkgPath string, typePlugins map[*tipe.Named]string) (pkgb, mainb []byte, err error) { 1161 p := &printer{ 1162 buf: new(bytes.Buffer), 1163 imports: make(map[*tipe.Package]string), 1164 eliders: make(map[tipe.Type]string), 1165 underlying: true, 1166 typeCur: t, 1167 typePlugins: typePlugins, 1168 typePluginsUsed: make(map[*tipe.Named]bool), 1169 } 1170 1171 p.printf("var Zero %s", t.Name) 1172 p.newline() 1173 p.newline() 1174 1175 p.printf("type %s ", t.Name) 1176 p.tipe(tipe.Underlying(t.Type)) 1177 1178 for _, mOrig := range methods { 1179 p.newline() 1180 p.newline() 1181 1182 m := new(expr.FuncLiteral) 1183 *m = *mOrig 1184 m.PointerReceiver = true 1185 for i := range m.ParamNames { 1186 if m.ParamNames[i] == "" { 1187 m.ParamNames[i] = fmt.Sprintf("gengo_param_%d", i) 1188 } 1189 } 1190 for i := range m.ResultNames { 1191 if m.ResultNames[i] == "" { 1192 m.ResultNames[i] = fmt.Sprintf("gengo_result_%d", i) 1193 } 1194 } 1195 m.Body = nil 1196 p.funcLiteral(m, t.Name) 1197 p.printf(" {") 1198 p.indent++ 1199 p.newline() 1200 1201 p.printf("gengo_in := make([]reflect.Value, %d)", 1+len(m.ParamNames)) 1202 p.newline() 1203 p.printf("gengo_in[0] = reflect.ValueOf(unsafe.Pointer(%s))", m.ReceiverName) 1204 for i, name := range m.ParamNames { 1205 p.newline() 1206 p.printf("gengo_in[%d] = reflect.ValueOf(%s)", 1+i, name) 1207 } 1208 p.newline() 1209 if len(m.ResultNames) > 0 { 1210 p.printf("var res interface{}") 1211 p.newline() 1212 p.printf("gengo_out := ") 1213 } 1214 p.printf("Type_Method_%s.Call(gengo_in)", m.Name) 1215 for i, name := range m.ResultNames { 1216 p.newline() 1217 p.printf("res = gengo_out[%d].Interface()", i) 1218 p.newline() 1219 p.printf("if res != nil {") 1220 p.indent++ 1221 p.newline() 1222 p.printf("%s = gengo_out[%d].Interface().(", name, i) 1223 p.tipe(m.Type.Results.Elems[i]) 1224 p.printf(")") 1225 p.indent-- 1226 p.newline() 1227 p.printf("}") 1228 } 1229 1230 p.newline() 1231 p.printf("return ") 1232 for i, name := range m.ResultNames { 1233 if i > 0 { 1234 p.printf(", ") 1235 } 1236 p.printf("%s", name) 1237 } 1238 1239 p.indent-- 1240 p.newline() 1241 p.printf("}") 1242 } 1243 1244 p.newline() 1245 p.newline() 1246 p.printf("var (") 1247 p.indent++ 1248 for _, m := range methods { 1249 p.newline() 1250 p.printf("Type_Method_%s reflect.Value", m.Name) 1251 } 1252 p.indent-- 1253 p.newline() 1254 p.printf(")") 1255 1256 rem := p.buf.Bytes() 1257 p.buf = new(bytes.Buffer) 1258 1259 // Put file header on after building contents so we know what 1260 // packages to import. 1261 p.printf("// generated by ng, do not edit") 1262 p.newline() 1263 p.newline() 1264 p.printf("package %s", t.Name) 1265 p.newline() 1266 p.newline() 1267 1268 imports := []string{} 1269 if len(methods) > 0 { 1270 imports = append(imports, "reflect", "unsafe") 1271 } 1272 for t := range p.typePluginsUsed { 1273 imports = append(imports, p.typePlugins[t]) 1274 } 1275 sort.Strings(imports) 1276 p.printf("import (") 1277 p.indent++ 1278 for _, imp := range imports { 1279 p.newline() 1280 p.printf("%q", imp) 1281 } 1282 p.indent-- 1283 p.newline() 1284 p.printf(")") 1285 p.newline() 1286 p.newline() 1287 1288 p.buf.Write(rem) 1289 1290 pkgb, err = goformat.Source(p.buf.Bytes()) 1291 fmt.Printf("pkgb: %s\n", pkgb) 1292 if err != nil { 1293 lines := new(bytes.Buffer) 1294 for i, line := range strings.Split(p.buf.String(), "\n") { 1295 fmt.Fprintf(lines, "%3d: %s\n", i+1, line) 1296 } 1297 return nil, nil, fmt.Errorf("gengo: bad generated pkg source: %v\n%s", err, lines.String()) 1298 } 1299 1300 p.buf.Reset() 1301 p.printf("// generated by ng, do not edit") 1302 p.newline() 1303 p.newline() 1304 p.printf("package main") 1305 p.newline() 1306 p.newline() 1307 1308 p.printf("import (") 1309 p.indent++ 1310 p.newline() 1311 p.printf("%q", pkgPath) 1312 p.indent-- 1313 p.newline() 1314 p.printf(")") 1315 p.newline() 1316 p.newline() 1317 pkgImport := path.Base(pkgPath) 1318 p.printf("var Zero = %s.Zero", pkgImport) 1319 for _, m := range methods { 1320 p.newline() 1321 p.printf("var Type_Method_%s = &%s.Type_Method_%s", m.Name, pkgImport, m.Name) 1322 } 1323 1324 mainb, err = goformat.Source(p.buf.Bytes()) 1325 if err != nil { 1326 lines := new(bytes.Buffer) 1327 for i, line := range strings.Split(p.buf.String(), "\n") { 1328 fmt.Fprintf(lines, "%3d: %s\n", i+1, line) 1329 } 1330 return nil, nil, fmt.Errorf("gengo: bad generated source: %v\n%s", err, lines.String()) 1331 } 1332 1333 return pkgb, mainb, nil 1334 }