llcppsigfetch:-v

This commit is contained in:
luoliwoshang
2024-10-21 20:51:08 +08:00
parent 8840968e07
commit 72d176b77a
3 changed files with 205 additions and 17 deletions

View File

@@ -19,6 +19,7 @@ package main
import (
"fmt"
"io"
"log"
"os"
"path/filepath"
"strconv"
@@ -41,6 +42,10 @@ func main() {
printUsage()
return
}
if ags.Verbose {
log.SetFlags(0)
parse.SetDebug(parse.DbgFlagAll)
}
extract := false
out := false
@@ -74,9 +79,21 @@ func main() {
}
if extract {
runExtract(extractFile, isTemp, isCpp, out, otherArgs)
if ags.Verbose {
log.Println("runExtract: extractFile:", extractFile)
log.Println("isTemp:", isTemp)
log.Println("isCpp:", isCpp)
log.Println("out:", out)
log.Println("otherArgs:", otherArgs)
}
runExtract(extractFile, isTemp, isCpp, out, otherArgs, ags.Verbose)
} else {
runFromConfig(ags.CfgFile, ags.UseStdin, out)
if ags.Verbose {
log.Println("runFromConfig: config file:", ags.CfgFile)
log.Println("use stdin:", ags.UseStdin)
log.Println("output to file:", out)
}
runFromConfig(ags.CfgFile, ags.UseStdin, out, ags.Verbose)
}
}
@@ -109,7 +126,7 @@ func printUsage() {
fmt.Println("Note: The two usage modes are mutually exclusive. Use either [<config_file>] OR --extract, not both.")
}
func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
func runFromConfig(cfgFile string, useStdin bool, outputToFile bool, verbose bool) {
var data []byte
var err error
if useStdin {
@@ -117,6 +134,13 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
} else {
data, err = os.ReadFile(cfgFile)
}
if verbose {
if useStdin {
log.Println("runFromConfig: read from stdin")
} else {
log.Println("runFromConfig: read from file", cfgFile)
}
}
check(err)
conf, err := config.GetConf(data)
@@ -124,10 +148,21 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
defer conf.Delete()
if err != nil {
fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile)
log.Println("Failed to parse config file:", cfgFile)
os.Exit(1)
}
files := getHeaderFiles(conf.CFlags, conf.Include)
//todo(zzy): reuse the llcppsymg's cflags parse
cflag := ParseCFlags(conf.CFlags)
files, notFounds, err := cflag.GenHeaderFilePaths(conf.Include)
check(err)
if verbose {
log.Println("runFromConfig: header file paths", files)
if len(notFounds) > 0 {
log.Println("runFromConfig: not found header files", notFounds)
}
}
context := parse.NewContext(conf.Cplusplus)
err = context.ProcessFiles(files)
@@ -136,7 +171,7 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool) {
outputInfo(context, outputToFile)
}
func runExtract(file string, isTemp bool, isCpp bool, outToFile bool, otherArgs []string) {
func runExtract(file string, isTemp bool, isCpp bool, outToFile bool, otherArgs []string, verbose bool) {
cfg := &clangutils.Config{
File: file,
Args: otherArgs,
@@ -175,14 +210,46 @@ func outputResult(result *c.Char, outputToFile bool) {
}
}
func getHeaderFiles(cflags string, files []string) []string {
prefix := cflags
prefix = strings.TrimPrefix(prefix, "-I")
var paths []string
for _, f := range files {
paths = append(paths, filepath.Join(prefix, f))
// todo(zzy): reuse the llcppsymg's cflags parse https://github.com/goplus/llgo/pull/788
type CFlags struct {
Paths []string // Include Path
}
func ParseCFlags(cflags string) *CFlags {
parts := strings.Fields(cflags)
cf := &CFlags{}
for _, part := range parts {
if strings.HasPrefix(part, "-I") {
cf.Paths = append(cf.Paths, part[2:])
}
}
return paths
return cf
}
func (cf *CFlags) GenHeaderFilePaths(files []string) ([]string, []string, error) {
var foundPaths []string
var notFound []string
for _, file := range files {
var found bool
for _, path := range cf.Paths {
fullPath := filepath.Join(path, file)
if _, err := os.Stat(fullPath); err == nil {
foundPaths = append(foundPaths, fullPath)
found = true
break
}
}
if !found {
notFound = append(notFound, file)
}
}
if len(foundPaths) == 0 {
return nil, notFound, fmt.Errorf("failed to find any header files")
}
return foundPaths, notFound, nil
}
func outputInfo(context *parse.Context, outputToFile bool) {

View File

@@ -2,6 +2,7 @@ package parse
import (
"fmt"
"log"
"os"
"strings"
"unsafe"
@@ -64,6 +65,13 @@ type Config struct {
}
func NewConverter(config *clangutils.Config) (*Converter, error) {
if debugParse {
log.Println("NewConverter: config")
log.Println("config.File", config.File)
log.Println("config.Args", config.Args)
log.Println("config.IsCpp", config.IsCpp)
log.Println("config.Temp", config.Temp)
}
index, unit, err := clangutils.CreateTranslationUnit(config)
if err != nil {
return nil, err
@@ -79,7 +87,13 @@ func NewConverter(config *clangutils.Config) (*Converter, error) {
}
func (ct *Converter) Dispose() {
if debugParse {
log.Println("Dispose: ct.index")
}
ct.index.Dispose()
if debugParse {
log.Println("Dispose: ct.unit")
}
ct.unit.Dispose()
}
@@ -123,14 +137,23 @@ func (ct *Converter) UpdateLoc(cursor clang.Cursor) {
func (ct *Converter) GetCurFile() *ast.File {
if ct.curLoc.File == "" {
if debugParse {
log.Println("GetCurFile: NO FILE")
}
return nil
}
// todo(zzy): more efficient
for i, entry := range ct.Files {
if entry.Path == ct.curLoc.File {
if debugParse {
log.Println("GetCurFile: found", ct.curLoc.File)
}
return ct.Files[i].Doc
}
}
if debugParse {
log.Println("GetCurFile: Create New ast.File", ct.curLoc.File)
}
newDoc := &ast.File{}
ct.Files = append(ct.Files, &FileEntry{Path: ct.curLoc.File, Doc: newDoc})
return newDoc
@@ -219,6 +242,13 @@ func (ct *Converter) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResul
ct.UpdateLoc(cursor)
curFile := ct.GetCurFile()
if debugParse {
name := cursor.String()
defer name.Dispose()
log.Println("visitTop: Cursor:", c.GoString(name.CStr()))
}
if curFile == nil {
return clang.ChildVisit_Continue
}
@@ -227,27 +257,69 @@ func (ct *Converter) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResul
case clang.CursorInclusionDirective:
include := ct.ProcessInclude(cursor)
curFile.Includes = append(curFile.Includes, include)
if debugParse {
log.Println("visitTop: ProcessInclude END ", include.Path)
}
case clang.CursorMacroDefinition:
macro := ct.ProcessMacro(cursor)
curFile.Macros = append(curFile.Macros, macro)
if debugParse {
log.Println("visitTop: ProcessMacro END ", macro.Name, "Tokens Length:", len(macro.Tokens))
}
case clang.CursorEnumDecl:
enum := ct.ProcessEnumDecl(cursor)
curFile.Decls = append(curFile.Decls, enum)
if debugParse {
name := "anonymous"
if enum.Name != nil {
name = enum.Name.Name
}
log.Println("visitTop: ProcessEnumDecl END", name)
}
case clang.CursorClassDecl:
classDecl := ct.ProcessClassDecl(cursor)
curFile.Decls = append(curFile.Decls, classDecl)
if debugParse {
name := "anonymous"
if classDecl.Name != nil {
name = classDecl.Name.Name
}
log.Println("visitTop: ProcessClassDecl END", name)
}
case clang.CursorStructDecl:
structDecl := ct.ProcessStructDecl(cursor)
curFile.Decls = append(curFile.Decls, structDecl)
if debugParse {
name := "anonymous"
if structDecl.Name != nil {
name = structDecl.Name.Name
}
log.Println("visitTop: ProcessStructDecl END", name)
}
case clang.CursorUnionDecl:
unionDecl := ct.ProcessUnionDecl(cursor)
curFile.Decls = append(curFile.Decls, unionDecl)
if debugParse {
name := "anonymous"
if unionDecl.Name != nil {
name = unionDecl.Name.Name
}
log.Println("visitTop: ProcessUnionDecl END", name)
}
case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor:
// Handle functions and class methods (including out-of-class method)
// Example: void MyClass::myMethod() { ... } out-of-class method
curFile.Decls = append(curFile.Decls, ct.ProcessFuncDecl(cursor))
funcDecl := ct.ProcessFuncDecl(cursor)
curFile.Decls = append(curFile.Decls, funcDecl)
if debugParse {
log.Println("visitTop: ProcessFuncDecl END", funcDecl.Name.Name, funcDecl.MangledName, "isStatic:", funcDecl.IsStatic, "isInline:", funcDecl.IsInline)
}
case clang.CursorTypedefDecl:
curFile.Decls = append(curFile.Decls, ct.ProcessTypeDefDecl(cursor))
typedefDecl := ct.ProcessTypeDefDecl(cursor)
curFile.Decls = append(curFile.Decls, typedefDecl)
if debugParse {
log.Println("visitTop: ProcessTypeDefDecl END", typedefDecl.Name.Name)
}
case clang.CursorNamespace:
VisitChildren(cursor, ct.visitTop)
}
@@ -352,12 +424,17 @@ func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl {
}
ct.SetTypeDecl(cursor, decl)
return decl
}
func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
underlyingTyp := cursor.TypedefDeclUnderlyingType()
if underlyingTyp.Kind != clang.TypeElaborated {
if debugParse {
log.Println("ProcessUnderlyingType: not elaborated")
}
return ct.ProcessType(underlyingTyp)
}
@@ -370,6 +447,9 @@ func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
// In this case, libclang incorrectly reports an anonymous struct as a named struct
sourceCode := ct.GetTokens(referTypeCursor)
if isAnonymousStructure(sourceCode) {
if debugParse {
log.Println("ProcessUnderlyingType: is anonymous structure")
}
ct.SetAnonyType(referTypeCursor)
typ, isValidType := ct.GetTypeDecl(referTypeCursor)
if isValidType {
@@ -377,9 +457,15 @@ func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
// according to a normal anonymous decl
switch declType := typ.(type) {
case *ast.EnumTypeDecl:
if debugParse {
log.Println("ProcessUnderlyingType: is actually anonymous enum,remove name")
}
declType.Name = nil
case *ast.TypeDecl:
if declType.Type.Tag != ast.Class {
if debugParse {
log.Println("ProcessUnderlyingType: is actually anonymous struct,remove name")
}
declType.Name = nil
} else {
// Unreachable: There should be no anonymous classes in this context
@@ -405,11 +491,17 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
// function type will only collect return type
// ProcessType can't get the field names,will collect in follows
if debugParse {
log.Println("ProcessFuncDecl: Get Base FuncType")
}
funcType, ok := ct.ProcessType(cursor.Type()).(*ast.FuncType)
if !ok {
fmt.Println("failed to process function type")
return nil
}
if debugParse {
log.Println("ProcessFuncDecl: ProcessFieldList")
}
params := ct.ProcessFieldList(cursor)
funcType.Params = params
@@ -428,6 +520,9 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
}
if isMethod(cursor) {
if debugParse {
log.Println("ProcessFuncDecl: is method, ProcessMethodAttributes")
}
ct.ProcessMethodAttributes(cursor, funcDecl)
} else {
if cursor.StorageClass() == clang.SCStatic {
@@ -436,7 +531,6 @@ func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
}
ct.SetTypeDecl(cursor, funcDecl)
return funcDecl
}
@@ -675,7 +769,6 @@ func (ct *Converter) ProcessClassDecl(cursor clang.Cursor) *ast.TypeDecl {
Type: typ,
}
ct.SetTypeDecl(cursor, decl)
return decl
}

View File

@@ -2,11 +2,27 @@ package parse
import (
"errors"
"log"
"github.com/goplus/llgo/c/cjson"
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
)
type dbgFlags = int
const (
DbgParse dbgFlags = 1 << iota
DbgFlagAll = DbgParse
)
var (
debugParse bool
)
func SetDebug(dbgFlags dbgFlags) {
debugParse = (dbgFlags & DbgParse) != 0
}
type Context struct {
Files []*FileEntry
IsCpp bool
@@ -25,6 +41,9 @@ func (p *Context) Output() *cjson.JSON {
// ProcessFiles processes the given files and adds them to the context
func (p *Context) ProcessFiles(files []string) error {
if debugParse {
log.Println("ProcessFiles: files", files, "isCpp", p.IsCpp)
}
for _, file := range files {
if err := p.processFile(file); err != nil {
return err
@@ -35,8 +54,14 @@ func (p *Context) ProcessFiles(files []string) error {
// parse file and add it to the context,avoid duplicate parsing
func (p *Context) processFile(path string) error {
if debugParse {
log.Println("processFile: path", path)
}
for _, entry := range p.Files {
if entry.Path == path {
if debugParse {
log.Println("processFile: already parsed", path)
}
return nil
}
}
@@ -50,6 +75,9 @@ func (p *Context) processFile(path string) error {
}
func (p *Context) parseFile(path string) ([]*FileEntry, error) {
if debugParse {
log.Println("parseFile: path", path)
}
converter, err := NewConverter(&clangutils.Config{
File: path,
Temp: false,