func (p *fileParser) parseFunc(pkg string, f *ast.FuncType) (in []*model.Parameter, variadic *model.Parameter, out []*model.Parameter, err error) { if f.Params != nil { regParams := f.Params.List if isVariadic(f) { n := len(regParams) varParams := regParams[n-1:] regParams = regParams[:n-1] vp, err := p.parseFieldList(pkg, varParams) if err != nil { return nil, nil, nil, p.errorf(varParams[0].Pos(), "failed parsing variadic argument: %v", err) } variadic = vp[0] } in, err = p.parseFieldList(pkg, regParams) if err != nil { return nil, nil, nil, p.errorf(f.Pos(), "failed parsing arguments: %v", err) } } if f.Results != nil { out, err = p.parseFieldList(pkg, f.Results.List) if err != nil { return nil, nil, nil, p.errorf(f.Pos(), "failed parsing returns: %v", err) } } return }
func (p *parser) parseSignature(n *parse.Node, scope *ast.Scope) *ast.FuncType { funcType := ast.FuncType{ Params: p.parseParams(n.Child(0), scope), } if n.ChildCount() > 1 { funcType.Results = p.parseResults(n.Child(1), scope) } return &funcType }
func omitNoPassArgs(ft *ast.FuncType) *ast.FuncType { tmp := *ft // copy ft = &tmp tmp2 := *ft.Params ft.Params = &tmp2 var keepParams []*ast.Field for _, p := range ft.Params.List { if len(p.Names) == 1 && p.Names[0].Name == *noPassArgs { continue } keepParams = append(keepParams, p) } ft.Params.List = keepParams return ft }
func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { name := n.Go gtype := n.FuncType.Go if n.AddError { // Add "os.Error" to return type list. // Type list is known to be 0 or 1 element - it's a C function. err := &ast.Field{Type: ast.NewIdent("os.Error")} l := gtype.Results.List if len(l) == 0 { l = []*ast.Field{err} } else { l = []*ast.Field{l[0], err} } t := new(ast.FuncType) *t = *gtype t.Results = &ast.FieldList{List: l} gtype = t } // Go func declaration. d := &ast.FuncDecl{ Name: ast.NewIdent(n.Mangle), Type: gtype, } printer.Fprint(fgo2, fset, d) fmt.Fprintf(fgo2, "\n") if name == "CString" || name == "GoString" || name == "GoStringN" { // The builtins are already defined in the C prolog. return } var argSize int64 _, argSize = p.structType(n) // C wrapper calls into gcc, passing a pointer to the argument frame. fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) fmt.Fprintf(fc, "\n") fmt.Fprintf(fc, "void\n") if argSize == 0 { argSize++ } fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize) fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) if n.AddError { // gcc leaves errno in first word of interface at end of p. // check whether it is zero; if so, turn interface into nil. // if not, turn interface into errno. // Go init function initializes ·_Cerrno with an os.Errno // for us to copy. fmt.Fprintln(fc, ` { int32 e; void **v; v = (void**)(&p+1) - 2; /* v = final two void* of p */ e = *(int32*)v; v[0] = (void*)0xdeadbeef; v[1] = (void*)0xdeadbeef; if(e == 0) { /* nil interface */ v[0] = 0; v[1] = 0; } else { ·_Cerrno(v, e); /* fill in v as os.Error for errno e */ } }`) } fmt.Fprintf(fc, "}\n") fmt.Fprintf(fc, "\n") }
func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) { name := n.Go gtype := n.FuncType.Go void := gtype.Results == nil || len(gtype.Results.List) == 0 if n.AddError { // Add "error" to return type list. // Type list is known to be 0 or 1 element - it's a C function. err := &ast.Field{Type: ast.NewIdent("error")} l := gtype.Results.List if len(l) == 0 { l = []*ast.Field{err} } else { l = []*ast.Field{l[0], err} } t := new(ast.FuncType) *t = *gtype t.Results = &ast.FieldList{List: l} gtype = t } // Go func declaration. d := &ast.FuncDecl{ Name: ast.NewIdent(n.Mangle), Type: gtype, } // Builtins defined in the C prolog. inProlog := builtinDefs[name] != "" cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) paramnames := []string(nil) for i, param := range d.Type.Params.List { paramName := fmt.Sprintf("p%d", i) param.Names = []*ast.Ident{ast.NewIdent(paramName)} paramnames = append(paramnames, paramName) } if *gccgo { // Gccgo style hooks. fmt.Fprint(fgo2, "\n") conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") if !inProlog { fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") } if n.AddError { fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n") } fmt.Fprint(fgo2, "\t") if !void { fmt.Fprint(fgo2, "r := ") } fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", ")) if n.AddError { fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n") fmt.Fprint(fgo2, "\tif e != 0 {\n") fmt.Fprint(fgo2, "\t\treturn ") if !void { fmt.Fprint(fgo2, "r, ") } fmt.Fprint(fgo2, "e\n") fmt.Fprint(fgo2, "\t}\n") fmt.Fprint(fgo2, "\treturn ") if !void { fmt.Fprint(fgo2, "r, ") } fmt.Fprint(fgo2, "nil\n") } else if !void { fmt.Fprint(fgo2, "\treturn r\n") } fmt.Fprint(fgo2, "}\n") // declare the C function. fmt.Fprintf(fgo2, "//extern %s\n", cname) d.Name = ast.NewIdent(cname) if n.AddError { l := d.Type.Results.List d.Type.Results.List = l[:len(l)-1] } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") return } if inProlog { fmt.Fprint(fgo2, builtinDefs[name]) if strings.Contains(builtinDefs[name], "_cgo_cmalloc") { *callsMalloc = true } return } // Wrapper calls into gcc, passing a pointer to the argument frame. fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname) fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname) fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname) fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname) nret := 0 if !void { d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")} nret = 1 } if n.AddError { d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")} } fmt.Fprint(fgo2, "\n") fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n") conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") // NOTE: Using uintptr to hide from escape analysis. arg := "0" if len(paramnames) > 0 { arg = "uintptr(unsafe.Pointer(&p0))" } else if !void { arg = "uintptr(unsafe.Pointer(&r1))" } prefix := "" if n.AddError { prefix = "errno := " } fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg) if n.AddError { fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") } fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n") for i := range d.Type.Params.List { fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i) } fmt.Fprintf(fgo2, "\t}\n") fmt.Fprintf(fgo2, "\treturn\n") fmt.Fprintf(fgo2, "}\n") }
func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { name := n.Go gtype := n.FuncType.Go void := gtype.Results == nil || len(gtype.Results.List) == 0 if n.AddError { // Add "error" to return type list. // Type list is known to be 0 or 1 element - it's a C function. err := &ast.Field{Type: ast.NewIdent("error")} l := gtype.Results.List if len(l) == 0 { l = []*ast.Field{err} } else { l = []*ast.Field{l[0], err} } t := new(ast.FuncType) *t = *gtype t.Results = &ast.FieldList{List: l} gtype = t } // Go func declaration. d := &ast.FuncDecl{ Name: ast.NewIdent(n.Mangle), Type: gtype, } // Builtins defined in the C prolog. inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc" if *gccgo { // Gccgo style hooks. fmt.Fprint(fgo2, "\n") cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) paramnames := []string(nil) for i, param := range d.Type.Params.List { paramName := fmt.Sprintf("p%d", i) param.Names = []*ast.Ident{ast.NewIdent(paramName)} paramnames = append(paramnames, paramName) } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") if !inProlog { fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") } if n.AddError { fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n") } fmt.Fprint(fgo2, "\t") if !void { fmt.Fprint(fgo2, "r := ") } fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", ")) if n.AddError { fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n") fmt.Fprint(fgo2, "\tif e != 0 {\n") fmt.Fprint(fgo2, "\t\treturn ") if !void { fmt.Fprint(fgo2, "r, ") } fmt.Fprint(fgo2, "e\n") fmt.Fprint(fgo2, "\t}\n") fmt.Fprint(fgo2, "\treturn ") if !void { fmt.Fprint(fgo2, "r, ") } fmt.Fprint(fgo2, "nil\n") } else if !void { fmt.Fprint(fgo2, "\treturn r\n") } fmt.Fprint(fgo2, "}\n") // declare the C function. fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) d.Name = ast.NewIdent(cname) if n.AddError { l := d.Type.Results.List d.Type.Results.List = l[:len(l)-1] } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") return } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") if inProlog { return } var argSize int64 _, argSize = p.structType(n) // C wrapper calls into gcc, passing a pointer to the argument frame. fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle) fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) fmt.Fprintf(fc, "\n") fmt.Fprintf(fc, "void\n") if argSize == 0 { argSize++ } // TODO(rsc): The struct here should declare pointers only where // there are pointers in the actual argument frame. // This is a workaround for golang.org/issue/6397. fmt.Fprintf(fc, "·%s(struct{", n.Mangle) if n := argSize / p.PtrSize; n > 0 { fmt.Fprintf(fc, "void *y[%d];", n) } if n := argSize % p.PtrSize; n > 0 { fmt.Fprintf(fc, "uint8 x[%d];", n) } fmt.Fprintf(fc, "}p)\n") fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) if n.AddError { // gcc leaves errno in first word of interface at end of p. // check whether it is zero; if so, turn interface into nil. // if not, turn interface into errno. // Go init function initializes ·_Cerrno with an os.Errno // for us to copy. fmt.Fprintln(fc, ` { int32 e; void **v; v = (void**)(&p+1) - 2; /* v = final two void* of p */ e = *(int32*)v; v[0] = (void*)0xdeadbeef; v[1] = (void*)0xdeadbeef; if(e == 0) { /* nil interface */ v[0] = 0; v[1] = 0; } else { ·_Cerrno(v, e); /* fill in v as error for errno e */ } }`) } fmt.Fprintf(fc, "}\n") fmt.Fprintf(fc, "\n") }
func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { name := n.Go gtype := n.FuncType.Go if n.AddError { // Add "error" to return type list. // Type list is known to be 0 or 1 element - it's a C function. err := &ast.Field{Type: ast.NewIdent("error")} l := gtype.Results.List if len(l) == 0 { l = []*ast.Field{err} } else { l = []*ast.Field{l[0], err} } t := new(ast.FuncType) *t = *gtype t.Results = &ast.FieldList{List: l} gtype = t } // Go func declaration. d := &ast.FuncDecl{ Name: ast.NewIdent(n.Mangle), Type: gtype, } if *gccgo { // Gccgo style hooks. // we hook directly into C. gccgo goes not support cgocall yet. if !n.AddError { fmt.Fprintf(fgo2, "//extern %s\n", n.C) conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") } else { // write a small wrapper to retrieve errno. cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) paramnames := []string(nil) for i, param := range d.Type.Params.List { paramName := fmt.Sprintf("p%d", i) param.Names = []*ast.Ident{ast.NewIdent(paramName)} paramnames = append(paramnames, paramName) } conf.Fprint(fgo2, fset, d) fmt.Fprintf(fgo2, "{\n") fmt.Fprintf(fgo2, "\tsyscall.SetErrno(0)\n") fmt.Fprintf(fgo2, "\tr := %s(%s)\n", cname, strings.Join(paramnames, ", ")) fmt.Fprintf(fgo2, "\te := syscall.GetErrno()\n") fmt.Fprintf(fgo2, "\tif e != 0 {\n") fmt.Fprintf(fgo2, "\t\treturn r, e\n") fmt.Fprintf(fgo2, "\t}\n") fmt.Fprintf(fgo2, "\treturn r, nil\n") fmt.Fprintf(fgo2, "}\n") // declare the C function. fmt.Fprintf(fgo2, "//extern %s\n", n.C) d.Name = ast.NewIdent(cname) l := d.Type.Results.List d.Type.Results.List = l[:len(l)-1] conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") } return } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" { // The builtins are already defined in the C prolog. return } var argSize int64 _, argSize = p.structType(n) // C wrapper calls into gcc, passing a pointer to the argument frame. fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) fmt.Fprintf(fc, "\n") fmt.Fprintf(fc, "void\n") if argSize == 0 { argSize++ } fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize) fmt.Fprintf(fc, "{\n") fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) if n.AddError { // gcc leaves errno in first word of interface at end of p. // check whether it is zero; if so, turn interface into nil. // if not, turn interface into errno. // Go init function initializes ·_Cerrno with an os.Errno // for us to copy. fmt.Fprintln(fc, ` { int32 e; void **v; v = (void**)(&p+1) - 2; /* v = final two void* of p */ e = *(int32*)v; v[0] = (void*)0xdeadbeef; v[1] = (void*)0xdeadbeef; if(e == 0) { /* nil interface */ v[0] = 0; v[1] = 0; } else { ·_Cerrno(v, e); /* fill in v as error for errno e */ } }`) } fmt.Fprintf(fc, "}\n") fmt.Fprintf(fc, "\n") }