llcppsymg:improve parsing process
This commit is contained in:
@@ -22,7 +22,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@@ -61,11 +60,11 @@ func main() {
|
|||||||
|
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
filepaths := generateHeaderFilePath(conf.CFlags, conf.Include)
|
filepaths := genHeaderFilePath(conf.CFlags, conf.Include)
|
||||||
astInfos, err := parse.ParseHeaderFile(filepaths)
|
headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
symbolInfo := getCommonSymbols(symbols, astInfos, conf.TrimPrefixes)
|
symbolInfo := getCommonSymbols(symbols, headerInfos, conf.TrimPrefixes)
|
||||||
|
|
||||||
err = genSymbolTableFile(symbolInfo)
|
err = genSymbolTableFile(symbolInfo)
|
||||||
check(err)
|
check(err)
|
||||||
@@ -77,8 +76,8 @@ func check(err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) {
|
func parseDylibSymbols(lib string) ([]*nm.Symbol, error) {
|
||||||
dylibPath, err := generateDylibPath(lib)
|
dylibPath, err := genDylibPath(lib)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to generate dylib path")
|
return nil, errors.New("failed to generate dylib path")
|
||||||
}
|
}
|
||||||
@@ -88,22 +87,15 @@ func parseDylibSymbols(lib string) ([]types.CPPSymbol, error) {
|
|||||||
return nil, errors.New("failed to list symbols in dylib")
|
return nil, errors.New("failed to list symbols in dylib")
|
||||||
}
|
}
|
||||||
|
|
||||||
var symbols []types.CPPSymbol
|
var symbols []*nm.Symbol
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
for _, sym := range file.Symbols {
|
symbols = append(symbols, file.Symbols...)
|
||||||
demangleName := decodeSymbolName(sym.Name)
|
|
||||||
symbols = append(symbols, types.CPPSymbol{
|
|
||||||
Symbol: sym,
|
|
||||||
DemangleName: demangleName,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbols, nil
|
return symbols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateDylibPath(lib string) (string, error) {
|
func genDylibPath(lib string) (string, error) {
|
||||||
output := lib
|
output := lib
|
||||||
libPath := ""
|
libPath := ""
|
||||||
libName := ""
|
libName := ""
|
||||||
@@ -123,31 +115,20 @@ func generateDylibPath(lib string) (string, error) {
|
|||||||
return dylibPath, nil
|
return dylibPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeSymbolName(symbolName string) string {
|
func decodeSymbol(symbolName string) string {
|
||||||
if symbolName == "" {
|
if symbolName == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
demangled := llvm.ItaniumDemangle(symbolName, true)
|
demangled := llvm.ItaniumDemangle(symbolName, true)
|
||||||
if demangled == nil {
|
if demangled == nil {
|
||||||
return symbolName
|
return symbolName
|
||||||
}
|
}
|
||||||
defer c.Free(unsafe.Pointer(demangled))
|
defer c.Free(unsafe.Pointer(demangled))
|
||||||
|
|
||||||
demangleName := c.GoString(demangled)
|
demangleName := c.GoString(demangled)
|
||||||
if demangleName == "" {
|
return strings.TrimSpace(demangleName)
|
||||||
return symbolName
|
|
||||||
}
|
|
||||||
|
|
||||||
decodedName := strings.TrimSpace(demangleName)
|
|
||||||
decodedName = strings.ReplaceAll(decodedName,
|
|
||||||
"std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const",
|
|
||||||
"std::string")
|
|
||||||
|
|
||||||
return decodedName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateHeaderFilePath(cflags string, files []string) []string {
|
func genHeaderFilePath(cflags string, files []string) []string {
|
||||||
prefixPath := cflags
|
prefixPath := cflags
|
||||||
prefixPath = strings.TrimPrefix(prefixPath, "-I")
|
prefixPath = strings.TrimPrefix(prefixPath, "-I")
|
||||||
var includePaths []string
|
var includePaths []string
|
||||||
@@ -157,77 +138,23 @@ func generateHeaderFilePath(cflags string, files []string) []string {
|
|||||||
return includePaths
|
return includePaths
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCommonSymbols(dylibSymbols []types.CPPSymbol, astInfoList []types.ASTInformation, prefix []string) []types.SymbolInfo {
|
func getCommonSymbols(dylibSymbols []*nm.Symbol, symbolMap map[string]string, prefix []string) []*types.SymbolInfo {
|
||||||
var commonSymbols []types.SymbolInfo
|
var commonSymbols []*types.SymbolInfo
|
||||||
functionNameMap := make(map[string]int)
|
for _, dylibSym := range dylibSymbols {
|
||||||
|
symName := strings.TrimPrefix(dylibSym.Name, "_")
|
||||||
for _, astInfo := range astInfoList {
|
if goName, ok := symbolMap[symName]; ok {
|
||||||
for _, dylibSym := range dylibSymbols {
|
symbolInfo := &types.SymbolInfo{
|
||||||
if strings.TrimPrefix(dylibSym.Name, "_") == astInfo.Symbol {
|
Mangle: symName,
|
||||||
cppName := generateCPPName(astInfo)
|
CPP: decodeSymbol(dylibSym.Name),
|
||||||
functionNameMap[cppName]++
|
Go: goName,
|
||||||
symbolInfo := types.SymbolInfo{
|
|
||||||
Mangle: strings.TrimPrefix(dylibSym.Name, "_"),
|
|
||||||
CPP: cppName,
|
|
||||||
Go: generateMangle(astInfo, functionNameMap[cppName], prefix),
|
|
||||||
}
|
|
||||||
commonSymbols = append(commonSymbols, symbolInfo)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
commonSymbols = append(commonSymbols, symbolInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return commonSymbols
|
return commonSymbols
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateCPPName(astInfo types.ASTInformation) string {
|
func genSymbolTableFile(symbolInfos []*types.SymbolInfo) error {
|
||||||
cppName := astInfo.Name
|
|
||||||
if astInfo.Class != "" {
|
|
||||||
cppName = astInfo.Class + "::" + astInfo.Name
|
|
||||||
}
|
|
||||||
return cppName
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateMangle(astInfo types.ASTInformation, count int, prefixes []string) string {
|
|
||||||
astInfo.Class = removePrefix(astInfo.Class, prefixes)
|
|
||||||
astInfo.Name = removePrefix(astInfo.Name, prefixes)
|
|
||||||
res := ""
|
|
||||||
if astInfo.Class != "" {
|
|
||||||
if astInfo.Class == astInfo.Name {
|
|
||||||
res = "(*" + astInfo.Class + ")." + "Init"
|
|
||||||
if count > 1 {
|
|
||||||
res += "__" + strconv.Itoa(count-1)
|
|
||||||
}
|
|
||||||
} else if astInfo.Name == "~"+astInfo.Class {
|
|
||||||
res = "(*" + astInfo.Class + ")." + "Dispose"
|
|
||||||
if count > 1 {
|
|
||||||
res += "__" + strconv.Itoa(count-1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res = "(*" + astInfo.Class + ")." + astInfo.Name
|
|
||||||
if count > 1 {
|
|
||||||
res += "__" + strconv.Itoa(count-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res = astInfo.Name
|
|
||||||
if count > 1 {
|
|
||||||
res += "__" + strconv.Itoa(count-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func removePrefix(str string, prefixes []string) string {
|
|
||||||
for _, prefix := range prefixes {
|
|
||||||
if strings.HasPrefix(str, prefix) {
|
|
||||||
return strings.TrimPrefix(str, prefix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
func genSymbolTableFile(symbolInfos []types.SymbolInfo) error {
|
|
||||||
// keep open follow code block can run successfully
|
// keep open follow code block can run successfully
|
||||||
for i := range symbolInfos {
|
for i := range symbolInfos {
|
||||||
println("symbol", symbolInfos[i].Go)
|
println("symbol", symbolInfos[i].Go)
|
||||||
@@ -269,6 +196,7 @@ func genSymbolTableFile(symbolInfos []types.SymbolInfo) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, error) {
|
func readExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, error) {
|
||||||
existingSymbols := make(map[string]types.SymbolInfo)
|
existingSymbols := make(map[string]types.SymbolInfo)
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,27 @@ package parse
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
"github.com/goplus/llgo/c/clang"
|
"github.com/goplus/llgo/c/clang"
|
||||||
"github.com/goplus/llgo/chore/llcppg/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
namespaceName string
|
namespaceName string
|
||||||
className string
|
className string
|
||||||
astInfo []types.ASTInformation
|
prefixes []string
|
||||||
|
symbolMap map[string]string
|
||||||
currentFile string
|
currentFile string
|
||||||
|
nameCounts map[string]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext() *Context {
|
func newContext(prefixes []string) *Context {
|
||||||
return &Context{
|
return &Context{
|
||||||
astInfo: make([]types.ASTInformation, 0),
|
prefixes: prefixes,
|
||||||
|
symbolMap: make(map[string]string),
|
||||||
|
nameCounts: make(map[string]int),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,70 +39,83 @@ func (c *Context) setCurrentFile(filename string) {
|
|||||||
c.currentFile = filename
|
c.currentFile = filename
|
||||||
}
|
}
|
||||||
|
|
||||||
var context = newContext()
|
func (c *Context) removePrefix(str string) string {
|
||||||
|
for _, prefix := range c.prefixes {
|
||||||
|
if strings.HasPrefix(str, prefix) {
|
||||||
|
return strings.TrimPrefix(str, prefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
func collectFuncInfo(cursor clang.Cursor) types.ASTInformation {
|
func (c *Context) genGoName(name string) string {
|
||||||
|
class := c.removePrefix(c.className)
|
||||||
|
name = c.removePrefix(name)
|
||||||
|
|
||||||
info := types.ASTInformation{
|
var baseName string
|
||||||
Namespace: context.namespaceName,
|
if class == "" {
|
||||||
Class: context.className,
|
baseName = name
|
||||||
|
} else {
|
||||||
|
baseName = c.genMethodName(class, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.addSuffix(baseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) genMethodName(class, name string) string {
|
||||||
|
prefix := "(*" + class + ")."
|
||||||
|
if class == name {
|
||||||
|
return prefix + "Init"
|
||||||
|
}
|
||||||
|
if name == "~"+class {
|
||||||
|
return prefix + "Dispose"
|
||||||
|
}
|
||||||
|
return prefix + name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) addSuffix(name string) string {
|
||||||
|
c.nameCounts[name]++
|
||||||
|
count := c.nameCounts[name]
|
||||||
|
if count > 1 {
|
||||||
|
return name + "__" + strconv.Itoa(count-1)
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = newContext([]string{})
|
||||||
|
|
||||||
|
func collectFuncInfo(cursor clang.Cursor) {
|
||||||
cursorStr := cursor.String()
|
cursorStr := cursor.String()
|
||||||
symbol := cursor.Mangling()
|
symbol := cursor.Mangling()
|
||||||
|
|
||||||
info.Name = c.GoString(cursorStr.CStr())
|
name := c.GoString(cursorStr.CStr())
|
||||||
|
symbolName := c.GoString(symbol.CStr())
|
||||||
info.Symbol = c.GoString(symbol.CStr())
|
if len(symbolName) >= 1 && symbolName[0] == '_' {
|
||||||
if len(info.Symbol) >= 1 {
|
symbolName = symbolName[1:]
|
||||||
if info.Symbol[0] == '_' {
|
|
||||||
info.Symbol = info.Symbol[1:]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defer symbol.Dispose()
|
defer symbol.Dispose()
|
||||||
defer cursorStr.Dispose()
|
defer cursorStr.Dispose()
|
||||||
|
|
||||||
if context.namespaceName != "" {
|
goName := context.genGoName(name)
|
||||||
info.Namespace = context.namespaceName
|
context.symbolMap[symbolName] = goName
|
||||||
}
|
|
||||||
if context.className != "" {
|
|
||||||
info.Class = context.className
|
|
||||||
}
|
|
||||||
|
|
||||||
typeStr := cursor.ResultType().String()
|
|
||||||
defer typeStr.Dispose()
|
|
||||||
info.ReturnType = c.GoString(typeStr.CStr())
|
|
||||||
|
|
||||||
info.Parameters = make([]types.Parameter, cursor.NumArguments())
|
|
||||||
for i := 0; i < int(cursor.NumArguments()); i++ {
|
|
||||||
argCurSor := cursor.Argument(c.Uint(i))
|
|
||||||
argType := argCurSor.Type().String()
|
|
||||||
argName := argCurSor.String()
|
|
||||||
info.Parameters[i] = types.Parameter{
|
|
||||||
Name: c.GoString(argName.CStr()),
|
|
||||||
Type: c.GoString(argType.CStr()),
|
|
||||||
}
|
|
||||||
|
|
||||||
argType.Dispose()
|
|
||||||
argName.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
return info
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
||||||
if cursor.Kind == clang.Namespace {
|
if cursor.Kind == clang.CursorNamespace {
|
||||||
nameStr := cursor.String()
|
nameStr := cursor.String()
|
||||||
|
defer nameStr.Dispose()
|
||||||
|
|
||||||
context.setNamespaceName(c.GoString(nameStr.CStr()))
|
context.setNamespaceName(c.GoString(nameStr.CStr()))
|
||||||
clang.VisitChildren(cursor, visit, nil)
|
clang.VisitChildren(cursor, visit, nil)
|
||||||
context.setNamespaceName("")
|
context.setNamespaceName("")
|
||||||
} else if cursor.Kind == clang.ClassDecl {
|
} else if cursor.Kind == clang.CursorClassDecl {
|
||||||
nameStr := cursor.String()
|
nameStr := cursor.String()
|
||||||
|
defer nameStr.Dispose()
|
||||||
|
|
||||||
context.setClassName(c.GoString(nameStr.CStr()))
|
context.setClassName(c.GoString(nameStr.CStr()))
|
||||||
clang.VisitChildren(cursor, visit, nil)
|
clang.VisitChildren(cursor, visit, nil)
|
||||||
context.setClassName("")
|
context.setClassName("")
|
||||||
} else if cursor.Kind == clang.CXXMethod || cursor.Kind == clang.FunctionDecl || cursor.Kind == clang.Constructor || cursor.Kind == clang.Destructor {
|
} else if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorFunctionDecl || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor {
|
||||||
loc := cursor.Location()
|
loc := cursor.Location()
|
||||||
var file clang.File
|
var file clang.File
|
||||||
var line, column c.Uint
|
var line, column c.Uint
|
||||||
@@ -107,9 +124,7 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe
|
|||||||
filename := file.FileName()
|
filename := file.FileName()
|
||||||
|
|
||||||
if c.Strcmp(filename.CStr(), c.AllocaCStr(context.currentFile)) == 0 {
|
if c.Strcmp(filename.CStr(), c.AllocaCStr(context.currentFile)) == 0 {
|
||||||
info := collectFuncInfo(cursor)
|
collectFuncInfo(cursor)
|
||||||
info.Location = c.GoString(filename.CStr()) + ":" + strconv.Itoa(int(line)) + ":" + strconv.Itoa(int(column))
|
|
||||||
context.astInfo = append(context.astInfo, info)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defer filename.Dispose()
|
defer filename.Dispose()
|
||||||
@@ -118,14 +133,13 @@ func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitRe
|
|||||||
return clang.ChildVisit_Continue
|
return clang.ChildVisit_Continue
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, error) {
|
func ParseHeaderFile(filepaths []string, prefixes []string) (map[string]string, error) {
|
||||||
|
|
||||||
index := clang.CreateIndex(0, 0)
|
index := clang.CreateIndex(0, 0)
|
||||||
args := make([]*c.Char, 3)
|
args := make([]*c.Char, 3)
|
||||||
args[0] = c.Str("-x")
|
args[0] = c.Str("-x")
|
||||||
args[1] = c.Str("c++")
|
args[1] = c.Str("c++")
|
||||||
args[2] = c.Str("-std=c++11")
|
args[2] = c.Str("-std=c++11")
|
||||||
context = newContext()
|
context = newContext(prefixes)
|
||||||
|
|
||||||
for _, filename := range filepaths {
|
for _, filename := range filepaths {
|
||||||
unit := index.ParseTranslationUnit(
|
unit := index.ParseTranslationUnit(
|
||||||
@@ -149,5 +163,5 @@ func ParseHeaderFile(filepaths []string) ([]types.ASTInformation, error) {
|
|||||||
|
|
||||||
index.Dispose()
|
index.Dispose()
|
||||||
|
|
||||||
return context.astInfo, nil
|
return context.symbolMap, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user