cgo: simplify construction of in-memory AST
Instead of writing the entire AST by hand, write it in Go code and parse it to create the base AST to build upon.
Этот коммит содержится в:
родитель
1789570f52
коммит
6bd18af5ef
1 изменённых файлов: 16 добавлений и 51 удалений
67
cgo/cgo.go
67
cgo/cgo.go
|
@ -14,6 +14,7 @@ package cgo
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
"go/token"
|
"go/token"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -162,6 +163,14 @@ typedef long long _Cgo_longlong;
|
||||||
typedef unsigned long long _Cgo_ulonglong;
|
typedef unsigned long long _Cgo_ulonglong;
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// First part of the generated Go file. Written here as Go because that's much
|
||||||
|
// easier than constructing the entire AST in memory.
|
||||||
|
const generatedGoFilePrefix = `
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
`
|
||||||
|
|
||||||
// Process extracts `import "C"` statements from the AST, parses the comment
|
// Process extracts `import "C"` statements from the AST, parses the comment
|
||||||
// with libclang, and modifies the AST to use this information. It returns a
|
// with libclang, and modifies the AST to use this information. It returns a
|
||||||
// newly created *ast.File that should be added to the list of to-be-parsed
|
// newly created *ast.File that should be added to the list of to-be-parsed
|
||||||
|
@ -202,57 +211,13 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||||
p.packageDir = filepath.Dir(packagePath)
|
p.packageDir = filepath.Dir(packagePath)
|
||||||
|
|
||||||
// Construct a new in-memory AST for CGo declarations of this package.
|
// Construct a new in-memory AST for CGo declarations of this package.
|
||||||
unsafeImport := &ast.ImportSpec{
|
// The first part is written as Go code that is then parsed, but more code
|
||||||
Path: &ast.BasicLit{
|
// is added later to the AST to declare functions, globals, etc.
|
||||||
ValuePos: p.generatedPos,
|
goCode := "package " + files[0].Name.Name + "\n\n" + generatedGoFilePrefix
|
||||||
Kind: token.STRING,
|
p.generated, err = parser.ParseFile(fset, dir+"/!cgo.go", goCode, parser.ParseComments)
|
||||||
Value: "\"unsafe\"",
|
if err != nil {
|
||||||
},
|
// This is always a bug in the cgo package.
|
||||||
EndPos: p.generatedPos,
|
panic("unexpected error: " + err.Error())
|
||||||
}
|
|
||||||
p.generated = &ast.File{
|
|
||||||
Package: p.generatedPos,
|
|
||||||
Name: &ast.Ident{
|
|
||||||
NamePos: p.generatedPos,
|
|
||||||
Name: files[0].Name.Name,
|
|
||||||
},
|
|
||||||
Decls: []ast.Decl{
|
|
||||||
// import "unsafe"
|
|
||||||
&ast.GenDecl{
|
|
||||||
TokPos: p.generatedPos,
|
|
||||||
Tok: token.IMPORT,
|
|
||||||
Specs: []ast.Spec{
|
|
||||||
unsafeImport,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// var _ unsafe.Pointer
|
|
||||||
// This avoids type errors when the unsafe package is never used.
|
|
||||||
&ast.GenDecl{
|
|
||||||
Tok: token.VAR,
|
|
||||||
Specs: []ast.Spec{
|
|
||||||
&ast.ValueSpec{
|
|
||||||
Names: []*ast.Ident{
|
|
||||||
{
|
|
||||||
Name: "_",
|
|
||||||
Obj: &ast.Object{
|
|
||||||
Kind: ast.Var,
|
|
||||||
Name: "_",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Type: &ast.SelectorExpr{
|
|
||||||
X: &ast.Ident{
|
|
||||||
Name: "unsafe",
|
|
||||||
},
|
|
||||||
Sel: &ast.Ident{
|
|
||||||
Name: "Pointer",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Imports: []*ast.ImportSpec{unsafeImport},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all C.* symbols.
|
// Find all C.* symbols.
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче