summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/gopherjs/gopherjs/compiler/package.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/gopherjs/gopherjs/compiler/package.go')
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/gopherjs/gopherjs/compiler/package.go809
1 files changed, 809 insertions, 0 deletions
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/gopherjs/gopherjs/compiler/package.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/gopherjs/gopherjs/compiler/package.go
new file mode 100644
index 00000000000..f841b145b4b
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/gopherjs/gopherjs/compiler/package.go
@@ -0,0 +1,809 @@
+package compiler
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "go/ast"
+ "go/constant"
+ "go/token"
+ "go/types"
+ "sort"
+ "strings"
+
+ "github.com/gopherjs/gopherjs/compiler/analysis"
+ "github.com/neelance/astrewrite"
+ "golang.org/x/tools/go/gcexportdata"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+type pkgContext struct {
+ *analysis.Info
+ additionalSelections map[*ast.SelectorExpr]selection
+
+ typeNames []*types.TypeName
+ pkgVars map[string]string
+ objectNames map[types.Object]string
+ varPtrNames map[*types.Var]string
+ anonTypes []*types.TypeName
+ anonTypeMap typeutil.Map
+ escapingVars map[*types.Var]bool
+ indentation int
+ dependencies map[types.Object]bool
+ minify bool
+ fileSet *token.FileSet
+ errList ErrorList
+}
+
+func (p *pkgContext) SelectionOf(e *ast.SelectorExpr) (selection, bool) {
+ if sel, ok := p.Selections[e]; ok {
+ return sel, true
+ }
+ if sel, ok := p.additionalSelections[e]; ok {
+ return sel, true
+ }
+ return nil, false
+}
+
+type selection interface {
+ Kind() types.SelectionKind
+ Recv() types.Type
+ Index() []int
+ Obj() types.Object
+ Type() types.Type
+}
+
+type fakeSelection struct {
+ kind types.SelectionKind
+ recv types.Type
+ index []int
+ obj types.Object
+ typ types.Type
+}
+
+func (sel *fakeSelection) Kind() types.SelectionKind { return sel.kind }
+func (sel *fakeSelection) Recv() types.Type { return sel.recv }
+func (sel *fakeSelection) Index() []int { return sel.index }
+func (sel *fakeSelection) Obj() types.Object { return sel.obj }
+func (sel *fakeSelection) Type() types.Type { return sel.typ }
+
+type funcContext struct {
+ *analysis.FuncInfo
+ p *pkgContext
+ parent *funcContext
+ sig *types.Signature
+ allVars map[string]int
+ localVars []string
+ resultNames []ast.Expr
+ flowDatas map[*types.Label]*flowData
+ caseCounter int
+ labelCases map[*types.Label]int
+ output []byte
+ delayedOutput []byte
+ posAvailable bool
+ pos token.Pos
+}
+
+type flowData struct {
+ postStmt func()
+ beginCase int
+ endCase int
+}
+
+type ImportContext struct {
+ Packages map[string]*types.Package
+ Import func(string) (*Archive, error)
+}
+
+// packageImporter implements go/types.Importer interface.
+type packageImporter struct {
+ importContext *ImportContext
+ importError *error // A pointer to importError in Compile.
+}
+
+func (pi packageImporter) Import(path string) (*types.Package, error) {
+ if path == "unsafe" {
+ return types.Unsafe, nil
+ }
+
+ a, err := pi.importContext.Import(path)
+ if err != nil {
+ if *pi.importError == nil {
+ // If import failed, show first error of import only (https://github.com/gopherjs/gopherjs/issues/119).
+ *pi.importError = err
+ }
+ return nil, err
+ }
+
+ return pi.importContext.Packages[a.ImportPath], nil
+}
+
+func Compile(importPath string, files []*ast.File, fileSet *token.FileSet, importContext *ImportContext, minify bool) (*Archive, error) {
+ typesInfo := &types.Info{
+ Types: make(map[ast.Expr]types.TypeAndValue),
+ Defs: make(map[*ast.Ident]types.Object),
+ Uses: make(map[*ast.Ident]types.Object),
+ Implicits: make(map[ast.Node]types.Object),
+ Selections: make(map[*ast.SelectorExpr]*types.Selection),
+ Scopes: make(map[ast.Node]*types.Scope),
+ }
+
+ var importError error
+ var errList ErrorList
+ var previousErr error
+ config := &types.Config{
+ Importer: packageImporter{
+ importContext: importContext,
+ importError: &importError,
+ },
+ Sizes: sizes32,
+ Error: func(err error) {
+ if previousErr != nil && previousErr.Error() == err.Error() {
+ return
+ }
+ errList = append(errList, err)
+ previousErr = err
+ },
+ }
+ typesPkg, err := config.Check(importPath, fileSet, files, typesInfo)
+ if importError != nil {
+ return nil, importError
+ }
+ if errList != nil {
+ if len(errList) > 10 {
+ pos := token.NoPos
+ if last, ok := errList[9].(types.Error); ok {
+ pos = last.Pos
+ }
+ errList = append(errList[:10], types.Error{Fset: fileSet, Pos: pos, Msg: "too many errors"})
+ }
+ return nil, errList
+ }
+ if err != nil {
+ return nil, err
+ }
+ importContext.Packages[importPath] = typesPkg
+
+ exportData := new(bytes.Buffer)
+ if err := gcexportdata.Write(exportData, nil, typesPkg); err != nil {
+ return nil, fmt.Errorf("failed to write export data: %v", err)
+ }
+ encodedFileSet := new(bytes.Buffer)
+ if err := fileSet.Write(json.NewEncoder(encodedFileSet).Encode); err != nil {
+ return nil, err
+ }
+
+ simplifiedFiles := make([]*ast.File, len(files))
+ for i, file := range files {
+ simplifiedFiles[i] = astrewrite.Simplify(file, typesInfo, false)
+ }
+
+ isBlocking := func(f *types.Func) bool {
+ archive, err := importContext.Import(f.Pkg().Path())
+ if err != nil {
+ panic(err)
+ }
+ fullName := f.FullName()
+ for _, d := range archive.Declarations {
+ if string(d.FullName) == fullName {
+ return d.Blocking
+ }
+ }
+ panic(fullName)
+ }
+ pkgInfo := analysis.AnalyzePkg(simplifiedFiles, fileSet, typesInfo, typesPkg, isBlocking)
+ c := &funcContext{
+ FuncInfo: pkgInfo.InitFuncInfo,
+ p: &pkgContext{
+ Info: pkgInfo,
+ additionalSelections: make(map[*ast.SelectorExpr]selection),
+
+ pkgVars: make(map[string]string),
+ objectNames: make(map[types.Object]string),
+ varPtrNames: make(map[*types.Var]string),
+ escapingVars: make(map[*types.Var]bool),
+ indentation: 1,
+ dependencies: make(map[types.Object]bool),
+ minify: minify,
+ fileSet: fileSet,
+ },
+ allVars: make(map[string]int),
+ flowDatas: map[*types.Label]*flowData{nil: {}},
+ caseCounter: 1,
+ labelCases: make(map[*types.Label]int),
+ }
+ for name := range reservedKeywords {
+ c.allVars[name] = 1
+ }
+
+ // imports
+ var importDecls []*Decl
+ var importedPaths []string
+ for _, importedPkg := range typesPkg.Imports() {
+ if importedPkg == types.Unsafe {
+ // Prior to Go 1.9, unsafe import was excluded by Imports() method,
+ // but now we do it here to maintain previous behavior.
+ continue
+ }
+ c.p.pkgVars[importedPkg.Path()] = c.newVariableWithLevel(importedPkg.Name(), true)
+ importedPaths = append(importedPaths, importedPkg.Path())
+ }
+ sort.Strings(importedPaths)
+ for _, impPath := range importedPaths {
+ id := c.newIdent(fmt.Sprintf(`%s.$init`, c.p.pkgVars[impPath]), types.NewSignature(nil, nil, nil, false))
+ call := &ast.CallExpr{Fun: id}
+ c.Blocking[call] = true
+ c.Flattened[call] = true
+ importDecls = append(importDecls, &Decl{
+ Vars: []string{c.p.pkgVars[impPath]},
+ DeclCode: []byte(fmt.Sprintf("\t%s = $packages[\"%s\"];\n", c.p.pkgVars[impPath], impPath)),
+ InitCode: c.CatchOutput(1, func() { c.translateStmt(&ast.ExprStmt{X: call}, nil) }),
+ })
+ }
+
+ var functions []*ast.FuncDecl
+ var vars []*types.Var
+ for _, file := range simplifiedFiles {
+ for _, decl := range file.Decls {
+ switch d := decl.(type) {
+ case *ast.FuncDecl:
+ sig := c.p.Defs[d.Name].(*types.Func).Type().(*types.Signature)
+ var recvType types.Type
+ if sig.Recv() != nil {
+ recvType = sig.Recv().Type()
+ if ptr, isPtr := recvType.(*types.Pointer); isPtr {
+ recvType = ptr.Elem()
+ }
+ }
+ if sig.Recv() == nil {
+ c.objectName(c.p.Defs[d.Name].(*types.Func)) // register toplevel name
+ }
+ if !isBlank(d.Name) {
+ functions = append(functions, d)
+ }
+ case *ast.GenDecl:
+ switch d.Tok {
+ case token.TYPE:
+ for _, spec := range d.Specs {
+ o := c.p.Defs[spec.(*ast.TypeSpec).Name].(*types.TypeName)
+ c.p.typeNames = append(c.p.typeNames, o)
+ c.objectName(o) // register toplevel name
+ }
+ case token.VAR:
+ for _, spec := range d.Specs {
+ for _, name := range spec.(*ast.ValueSpec).Names {
+ if !isBlank(name) {
+ o := c.p.Defs[name].(*types.Var)
+ vars = append(vars, o)
+ c.objectName(o) // register toplevel name
+ }
+ }
+ }
+ case token.CONST:
+ // skip, constants are inlined
+ }
+ }
+ }
+ }
+
+ collectDependencies := func(f func()) []string {
+ c.p.dependencies = make(map[types.Object]bool)
+ f()
+ var deps []string
+ for o := range c.p.dependencies {
+ qualifiedName := o.Pkg().Path() + "." + o.Name()
+ if f, ok := o.(*types.Func); ok && f.Type().(*types.Signature).Recv() != nil {
+ deps = append(deps, qualifiedName+"~")
+ continue
+ }
+ deps = append(deps, qualifiedName)
+ }
+ sort.Strings(deps)
+ return deps
+ }
+
+ // variables
+ var varDecls []*Decl
+ varsWithInit := make(map[*types.Var]bool)
+ for _, init := range c.p.InitOrder {
+ for _, o := range init.Lhs {
+ varsWithInit[o] = true
+ }
+ }
+ for _, o := range vars {
+ var d Decl
+ if !o.Exported() {
+ d.Vars = []string{c.objectName(o)}
+ }
+ if c.p.HasPointer[o] && !o.Exported() {
+ d.Vars = append(d.Vars, c.varPtrName(o))
+ }
+ if _, ok := varsWithInit[o]; !ok {
+ d.DceDeps = collectDependencies(func() {
+ d.InitCode = []byte(fmt.Sprintf("\t\t%s = %s;\n", c.objectName(o), c.translateExpr(c.zeroValue(o.Type())).String()))
+ })
+ }
+ d.DceObjectFilter = o.Name()
+ varDecls = append(varDecls, &d)
+ }
+ for _, init := range c.p.InitOrder {
+ lhs := make([]ast.Expr, len(init.Lhs))
+ for i, o := range init.Lhs {
+ ident := ast.NewIdent(o.Name())
+ c.p.Defs[ident] = o
+ lhs[i] = c.setType(ident, o.Type())
+ varsWithInit[o] = true
+ }
+ var d Decl
+ d.DceDeps = collectDependencies(func() {
+ c.localVars = nil
+ d.InitCode = c.CatchOutput(1, func() {
+ c.translateStmt(&ast.AssignStmt{
+ Lhs: lhs,
+ Tok: token.DEFINE,
+ Rhs: []ast.Expr{init.Rhs},
+ }, nil)
+ })
+ d.Vars = append(d.Vars, c.localVars...)
+ })
+ if len(init.Lhs) == 1 {
+ if !analysis.HasSideEffect(init.Rhs, c.p.Info.Info) {
+ d.DceObjectFilter = init.Lhs[0].Name()
+ }
+ }
+ varDecls = append(varDecls, &d)
+ }
+
+ // functions
+ var funcDecls []*Decl
+ var mainFunc *types.Func
+ for _, fun := range functions {
+ o := c.p.Defs[fun.Name].(*types.Func)
+ funcInfo := c.p.FuncDeclInfos[o]
+ d := Decl{
+ FullName: o.FullName(),
+ Blocking: len(funcInfo.Blocking) != 0,
+ }
+ if fun.Recv == nil {
+ d.Vars = []string{c.objectName(o)}
+ d.DceObjectFilter = o.Name()
+ switch o.Name() {
+ case "main":
+ mainFunc = o
+ d.DceObjectFilter = ""
+ case "init":
+ d.InitCode = c.CatchOutput(1, func() {
+ id := c.newIdent("", types.NewSignature(nil, nil, nil, false))
+ c.p.Uses[id] = o
+ call := &ast.CallExpr{Fun: id}
+ if len(c.p.FuncDeclInfos[o].Blocking) != 0 {
+ c.Blocking[call] = true
+ }
+ c.translateStmt(&ast.ExprStmt{X: call}, nil)
+ })
+ d.DceObjectFilter = ""
+ }
+ }
+ if fun.Recv != nil {
+ recvType := o.Type().(*types.Signature).Recv().Type()
+ ptr, isPointer := recvType.(*types.Pointer)
+ namedRecvType, _ := recvType.(*types.Named)
+ if isPointer {
+ namedRecvType = ptr.Elem().(*types.Named)
+ }
+ d.DceObjectFilter = namedRecvType.Obj().Name()
+ if !fun.Name.IsExported() {
+ d.DceMethodFilter = o.Name() + "~"
+ }
+ }
+
+ d.DceDeps = collectDependencies(func() {
+ d.DeclCode = c.translateToplevelFunction(fun, funcInfo)
+ })
+ funcDecls = append(funcDecls, &d)
+ }
+ if typesPkg.Name() == "main" {
+ if mainFunc == nil {
+ return nil, fmt.Errorf("missing main function")
+ }
+ id := c.newIdent("", types.NewSignature(nil, nil, nil, false))
+ c.p.Uses[id] = mainFunc
+ call := &ast.CallExpr{Fun: id}
+ ifStmt := &ast.IfStmt{
+ Cond: c.newIdent("$pkg === $mainPkg", types.Typ[types.Bool]),
+ Body: &ast.BlockStmt{
+ List: []ast.Stmt{
+ &ast.ExprStmt{X: call},
+ &ast.AssignStmt{
+ Lhs: []ast.Expr{c.newIdent("$mainFinished", types.Typ[types.Bool])},
+ Tok: token.ASSIGN,
+ Rhs: []ast.Expr{c.newConst(types.Typ[types.Bool], constant.MakeBool(true))},
+ },
+ },
+ },
+ }
+ if len(c.p.FuncDeclInfos[mainFunc].Blocking) != 0 {
+ c.Blocking[call] = true
+ c.Flattened[ifStmt] = true
+ }
+ funcDecls = append(funcDecls, &Decl{
+ InitCode: c.CatchOutput(1, func() {
+ c.translateStmt(ifStmt, nil)
+ }),
+ })
+ }
+
+ // named types
+ var typeDecls []*Decl
+ for _, o := range c.p.typeNames {
+ if o.IsAlias() {
+ continue
+ }
+ typeName := c.objectName(o)
+ d := Decl{
+ Vars: []string{typeName},
+ DceObjectFilter: o.Name(),
+ }
+ d.DceDeps = collectDependencies(func() {
+ d.DeclCode = c.CatchOutput(0, func() {
+ typeName := c.objectName(o)
+ lhs := typeName
+ if isPkgLevel(o) {
+ lhs += " = $pkg." + encodeIdent(o.Name())
+ }
+ size := int64(0)
+ constructor := "null"
+ switch t := o.Type().Underlying().(type) {
+ case *types.Struct:
+ params := make([]string, t.NumFields())
+ for i := 0; i < t.NumFields(); i++ {
+ params[i] = fieldName(t, i) + "_"
+ }
+ constructor = fmt.Sprintf("function(%s) {\n\t\tthis.$val = this;\n\t\tif (arguments.length === 0) {\n", strings.Join(params, ", "))
+ for i := 0; i < t.NumFields(); i++ {
+ constructor += fmt.Sprintf("\t\t\tthis.%s = %s;\n", fieldName(t, i), c.translateExpr(c.zeroValue(t.Field(i).Type())).String())
+ }
+ constructor += "\t\t\treturn;\n\t\t}\n"
+ for i := 0; i < t.NumFields(); i++ {
+ constructor += fmt.Sprintf("\t\tthis.%[1]s = %[1]s_;\n", fieldName(t, i))
+ }
+ constructor += "\t}"
+ case *types.Basic, *types.Array, *types.Slice, *types.Chan, *types.Signature, *types.Interface, *types.Pointer, *types.Map:
+ size = sizes32.Sizeof(t)
+ }
+ c.Printf(`%s = $newType(%d, %s, "%s.%s", %t, "%s", %t, %s);`, lhs, size, typeKind(o.Type()), o.Pkg().Name(), o.Name(), o.Name() != "", o.Pkg().Path(), o.Exported(), constructor)
+ })
+ d.MethodListCode = c.CatchOutput(0, func() {
+ named := o.Type().(*types.Named)
+ if _, ok := named.Underlying().(*types.Interface); ok {
+ return
+ }
+ var methods []string
+ var ptrMethods []string
+ for i := 0; i < named.NumMethods(); i++ {
+ method := named.Method(i)
+ name := method.Name()
+ if reservedKeywords[name] {
+ name += "$"
+ }
+ pkgPath := ""
+ if !method.Exported() {
+ pkgPath = method.Pkg().Path()
+ }
+ t := method.Type().(*types.Signature)
+ entry := fmt.Sprintf(`{prop: "%s", name: %s, pkg: "%s", typ: $funcType(%s)}`, name, encodeString(method.Name()), pkgPath, c.initArgs(t))
+ if _, isPtr := t.Recv().Type().(*types.Pointer); isPtr {
+ ptrMethods = append(ptrMethods, entry)
+ continue
+ }
+ methods = append(methods, entry)
+ }
+ if len(methods) > 0 {
+ c.Printf("%s.methods = [%s];", c.typeName(named), strings.Join(methods, ", "))
+ }
+ if len(ptrMethods) > 0 {
+ c.Printf("%s.methods = [%s];", c.typeName(types.NewPointer(named)), strings.Join(ptrMethods, ", "))
+ }
+ })
+ switch t := o.Type().Underlying().(type) {
+ case *types.Array, *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Slice, *types.Signature, *types.Struct:
+ d.TypeInitCode = c.CatchOutput(0, func() {
+ c.Printf("%s.init(%s);", c.objectName(o), c.initArgs(t))
+ })
+ }
+ })
+ typeDecls = append(typeDecls, &d)
+ }
+
+ // anonymous types
+ for _, t := range c.p.anonTypes {
+ d := Decl{
+ Vars: []string{t.Name()},
+ DceObjectFilter: t.Name(),
+ }
+ d.DceDeps = collectDependencies(func() {
+ d.DeclCode = []byte(fmt.Sprintf("\t%s = $%sType(%s);\n", t.Name(), strings.ToLower(typeKind(t.Type())[5:]), c.initArgs(t.Type())))
+ })
+ typeDecls = append(typeDecls, &d)
+ }
+
+ var allDecls []*Decl
+ for _, d := range append(append(append(importDecls, typeDecls...), varDecls...), funcDecls...) {
+ d.DeclCode = removeWhitespace(d.DeclCode, minify)
+ d.MethodListCode = removeWhitespace(d.MethodListCode, minify)
+ d.TypeInitCode = removeWhitespace(d.TypeInitCode, minify)
+ d.InitCode = removeWhitespace(d.InitCode, minify)
+ allDecls = append(allDecls, d)
+ }
+
+ if len(c.p.errList) != 0 {
+ return nil, c.p.errList
+ }
+
+ return &Archive{
+ ImportPath: importPath,
+ Name: typesPkg.Name(),
+ Imports: importedPaths,
+ ExportData: exportData.Bytes(),
+ Declarations: allDecls,
+ FileSet: encodedFileSet.Bytes(),
+ Minified: minify,
+ }, nil
+}
+
+func (c *funcContext) initArgs(ty types.Type) string {
+ switch t := ty.(type) {
+ case *types.Array:
+ return fmt.Sprintf("%s, %d", c.typeName(t.Elem()), t.Len())
+ case *types.Chan:
+ return fmt.Sprintf("%s, %t, %t", c.typeName(t.Elem()), t.Dir()&types.SendOnly != 0, t.Dir()&types.RecvOnly != 0)
+ case *types.Interface:
+ methods := make([]string, t.NumMethods())
+ for i := range methods {
+ method := t.Method(i)
+ pkgPath := ""
+ if !method.Exported() {
+ pkgPath = method.Pkg().Path()
+ }
+ methods[i] = fmt.Sprintf(`{prop: "%s", name: "%s", pkg: "%s", typ: $funcType(%s)}`, method.Name(), method.Name(), pkgPath, c.initArgs(method.Type()))
+ }
+ return fmt.Sprintf("[%s]", strings.Join(methods, ", "))
+ case *types.Map:
+ return fmt.Sprintf("%s, %s", c.typeName(t.Key()), c.typeName(t.Elem()))
+ case *types.Pointer:
+ return fmt.Sprintf("%s", c.typeName(t.Elem()))
+ case *types.Slice:
+ return fmt.Sprintf("%s", c.typeName(t.Elem()))
+ case *types.Signature:
+ params := make([]string, t.Params().Len())
+ for i := range params {
+ params[i] = c.typeName(t.Params().At(i).Type())
+ }
+ results := make([]string, t.Results().Len())
+ for i := range results {
+ results[i] = c.typeName(t.Results().At(i).Type())
+ }
+ return fmt.Sprintf("[%s], [%s], %t", strings.Join(params, ", "), strings.Join(results, ", "), t.Variadic())
+ case *types.Struct:
+ pkgPath := ""
+ fields := make([]string, t.NumFields())
+ for i := range fields {
+ field := t.Field(i)
+ if !field.Exported() {
+ pkgPath = field.Pkg().Path()
+ }
+ fields[i] = fmt.Sprintf(`{prop: "%s", name: %s, embedded: %t, exported: %t, typ: %s, tag: %s}`, fieldName(t, i), encodeString(field.Name()), field.Anonymous(), field.Exported(), c.typeName(field.Type()), encodeString(t.Tag(i)))
+ }
+ return fmt.Sprintf(`"%s", [%s]`, pkgPath, strings.Join(fields, ", "))
+ default:
+ panic("invalid type")
+ }
+}
+
+func (c *funcContext) translateToplevelFunction(fun *ast.FuncDecl, info *analysis.FuncInfo) []byte {
+ o := c.p.Defs[fun.Name].(*types.Func)
+ sig := o.Type().(*types.Signature)
+ var recv *ast.Ident
+ if fun.Recv != nil && fun.Recv.List[0].Names != nil {
+ recv = fun.Recv.List[0].Names[0]
+ }
+
+ var joinedParams string
+ primaryFunction := func(funcRef string) []byte {
+ if fun.Body == nil {
+ return []byte(fmt.Sprintf("\t%s = function() {\n\t\t$throwRuntimeError(\"native function not implemented: %s\");\n\t};\n", funcRef, o.FullName()))
+ }
+
+ params, fun := translateFunction(fun.Type, recv, fun.Body, c, sig, info, funcRef)
+ joinedParams = strings.Join(params, ", ")
+ return []byte(fmt.Sprintf("\t%s = %s;\n", funcRef, fun))
+ }
+
+ code := bytes.NewBuffer(nil)
+
+ if fun.Recv == nil {
+ funcRef := c.objectName(o)
+ code.Write(primaryFunction(funcRef))
+ if fun.Name.IsExported() {
+ fmt.Fprintf(code, "\t$pkg.%s = %s;\n", encodeIdent(fun.Name.Name), funcRef)
+ }
+ return code.Bytes()
+ }
+
+ recvType := sig.Recv().Type()
+ ptr, isPointer := recvType.(*types.Pointer)
+ namedRecvType, _ := recvType.(*types.Named)
+ if isPointer {
+ namedRecvType = ptr.Elem().(*types.Named)
+ }
+ typeName := c.objectName(namedRecvType.Obj())
+ funName := fun.Name.Name
+ if reservedKeywords[funName] {
+ funName += "$"
+ }
+
+ if _, isStruct := namedRecvType.Underlying().(*types.Struct); isStruct {
+ code.Write(primaryFunction(typeName + ".ptr.prototype." + funName))
+ fmt.Fprintf(code, "\t%s.prototype.%s = function(%s) { return this.$val.%s(%s); };\n", typeName, funName, joinedParams, funName, joinedParams)
+ return code.Bytes()
+ }
+
+ if isPointer {
+ if _, isArray := ptr.Elem().Underlying().(*types.Array); isArray {
+ code.Write(primaryFunction(typeName + ".prototype." + funName))
+ fmt.Fprintf(code, "\t$ptrType(%s).prototype.%s = function(%s) { return (new %s(this.$get())).%s(%s); };\n", typeName, funName, joinedParams, typeName, funName, joinedParams)
+ return code.Bytes()
+ }
+ return primaryFunction(fmt.Sprintf("$ptrType(%s).prototype.%s", typeName, funName))
+ }
+
+ value := "this.$get()"
+ if isWrapped(recvType) {
+ value = fmt.Sprintf("new %s(%s)", typeName, value)
+ }
+ code.Write(primaryFunction(typeName + ".prototype." + funName))
+ fmt.Fprintf(code, "\t$ptrType(%s).prototype.%s = function(%s) { return %s.%s(%s); };\n", typeName, funName, joinedParams, value, funName, joinedParams)
+ return code.Bytes()
+}
+
+func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt, outerContext *funcContext, sig *types.Signature, info *analysis.FuncInfo, funcRef string) ([]string, string) {
+ if info == nil {
+ panic("nil info")
+ }
+
+ c := &funcContext{
+ FuncInfo: info,
+ p: outerContext.p,
+ parent: outerContext,
+ sig: sig,
+ allVars: make(map[string]int, len(outerContext.allVars)),
+ localVars: []string{},
+ flowDatas: map[*types.Label]*flowData{nil: {}},
+ caseCounter: 1,
+ labelCases: make(map[*types.Label]int),
+ }
+ for k, v := range outerContext.allVars {
+ c.allVars[k] = v
+ }
+ prevEV := c.p.escapingVars
+
+ var params []string
+ for _, param := range typ.Params.List {
+ if len(param.Names) == 0 {
+ params = append(params, c.newVariable("param"))
+ continue
+ }
+ for _, ident := range param.Names {
+ if isBlank(ident) {
+ params = append(params, c.newVariable("param"))
+ continue
+ }
+ params = append(params, c.objectName(c.p.Defs[ident]))
+ }
+ }
+
+ bodyOutput := string(c.CatchOutput(1, func() {
+ if len(c.Blocking) != 0 {
+ c.p.Scopes[body] = c.p.Scopes[typ]
+ c.handleEscapingVars(body)
+ }
+
+ if c.sig != nil && c.sig.Results().Len() != 0 && c.sig.Results().At(0).Name() != "" {
+ c.resultNames = make([]ast.Expr, c.sig.Results().Len())
+ for i := 0; i < c.sig.Results().Len(); i++ {
+ result := c.sig.Results().At(i)
+ c.Printf("%s = %s;", c.objectName(result), c.translateExpr(c.zeroValue(result.Type())).String())
+ id := ast.NewIdent("")
+ c.p.Uses[id] = result
+ c.resultNames[i] = c.setType(id, result.Type())
+ }
+ }
+
+ if recv != nil && !isBlank(recv) {
+ this := "this"
+ if isWrapped(c.p.TypeOf(recv)) {
+ this = "this.$val"
+ }
+ c.Printf("%s = %s;", c.translateExpr(recv), this)
+ }
+
+ c.translateStmtList(body.List)
+ if len(c.Flattened) != 0 && !endsWithReturn(body.List) {
+ c.translateStmt(&ast.ReturnStmt{}, nil)
+ }
+ }))
+
+ sort.Strings(c.localVars)
+
+ var prefix, suffix, functionName string
+
+ if len(c.Flattened) != 0 {
+ c.localVars = append(c.localVars, "$s")
+ prefix = prefix + " $s = 0;"
+ }
+
+ if c.HasDefer {
+ c.localVars = append(c.localVars, "$deferred")
+ suffix = " }" + suffix
+ if len(c.Blocking) != 0 {
+ suffix = " }" + suffix
+ }
+ }
+
+ if len(c.Blocking) != 0 {
+ c.localVars = append(c.localVars, "$r")
+ if funcRef == "" {
+ funcRef = "$b"
+ functionName = " $b"
+ }
+ var stores, loads string
+ for _, v := range c.localVars {
+ loads += fmt.Sprintf("%s = $f.%s; ", v, v)
+ stores += fmt.Sprintf("$f.%s = %s; ", v, v)
+ }
+ prefix = prefix + " var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; " + loads + "}"
+ suffix = " if ($f === undefined) { $f = { $blk: " + funcRef + " }; } " + stores + "return $f;" + suffix
+ }
+
+ if c.HasDefer {
+ prefix = prefix + " var $err = null; try {"
+ deferSuffix := " } catch(err) { $err = err;"
+ if len(c.Blocking) != 0 {
+ deferSuffix += " $s = -1;"
+ }
+ if c.resultNames == nil && c.sig.Results().Len() > 0 {
+ deferSuffix += fmt.Sprintf(" return%s;", c.translateResults(nil))
+ }
+ deferSuffix += " } finally { $callDeferred($deferred, $err);"
+ if c.resultNames != nil {
+ deferSuffix += fmt.Sprintf(" if (!$curGoroutine.asleep) { return %s; }", c.translateResults(c.resultNames))
+ }
+ if len(c.Blocking) != 0 {
+ deferSuffix += " if($curGoroutine.asleep) {"
+ }
+ suffix = deferSuffix + suffix
+ }
+
+ if len(c.Flattened) != 0 {
+ prefix = prefix + " s: while (true) { switch ($s) { case 0:"
+ suffix = " } return; }" + suffix
+ }
+
+ if c.HasDefer {
+ prefix = prefix + " $deferred = []; $deferred.index = $curGoroutine.deferStack.length; $curGoroutine.deferStack.push($deferred);"
+ }
+
+ if prefix != "" {
+ bodyOutput = strings.Repeat("\t", c.p.indentation+1) + "/* */" + prefix + "\n" + bodyOutput
+ }
+ if suffix != "" {
+ bodyOutput = bodyOutput + strings.Repeat("\t", c.p.indentation+1) + "/* */" + suffix + "\n"
+ }
+ if len(c.localVars) != 0 {
+ bodyOutput = fmt.Sprintf("%svar %s;\n", strings.Repeat("\t", c.p.indentation+1), strings.Join(c.localVars, ", ")) + bodyOutput
+ }
+
+ c.p.escapingVars = prevEV
+
+ return params, fmt.Sprintf("function%s(%s) {\n%s%s}", functionName, strings.Join(params, ", "), bodyOutput, strings.Repeat("\t", c.p.indentation))
+}