diff options
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.go | 809 |
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)) +} |