llcppsigfetch:based on language configuration analysis
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
"github.com/goplus/llgo/c"
|
||||||
@@ -56,10 +57,14 @@ func printUsage() {
|
|||||||
fmt.Println(" If not provided, uses default 'llcppg.cfg'")
|
fmt.Println(" If not provided, uses default 'llcppg.cfg'")
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
fmt.Println(" --extract: Extract information from a single file")
|
fmt.Println(" --extract: Extract information from a single file")
|
||||||
fmt.Println(" <file>: When <temp> is false: the path to the file to process")
|
fmt.Println(" <file>: Path to the file to process, or file content if -temp=true")
|
||||||
fmt.Println(" When <temp> is true: the content of the file to process")
|
fmt.Println(" -temp=<bool>: Optional. Set to 'true' if <file> contains file content,")
|
||||||
fmt.Println(" <temp>: 'true' if <file> contains file content, 'false' if it's a file path")
|
fmt.Println(" 'false' (default) if it's a file path")
|
||||||
fmt.Println(" [args]: Optional additional arguments (default: -x c++ -std=c++11)")
|
fmt.Println(" -cpp=<bool>: Optional. Set to 'true' if the language is C++ (default: true)")
|
||||||
|
fmt.Println(" If not present, <file> is a file path")
|
||||||
|
fmt.Println(" [args]: Optional additional arguments")
|
||||||
|
fmt.Println(" Default for C++: -x c++")
|
||||||
|
fmt.Println(" Default for C: -x c")
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
fmt.Println(" --help, -h: Show this help message")
|
fmt.Println(" --help, -h: Show this help message")
|
||||||
fmt.Println("")
|
fmt.Println("")
|
||||||
@@ -91,7 +96,7 @@ func runFromConfig() {
|
|||||||
|
|
||||||
files := getHeaderFiles(conf.CFlags, conf.Include)
|
files := getHeaderFiles(conf.CFlags, conf.Include)
|
||||||
|
|
||||||
context := parse.NewContext()
|
context := parse.NewContext(conf.Cplusplus)
|
||||||
err = context.ProcessFiles(files)
|
err = context.ProcessFiles(files)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
@@ -99,21 +104,33 @@ func runFromConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runExtract() {
|
func runExtract() {
|
||||||
if len(os.Args) < 4 {
|
if len(os.Args) < 3 {
|
||||||
|
fmt.Println("Error: Insufficient arguments for --extract")
|
||||||
printUsage()
|
printUsage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &parse.Config{
|
cfg := &parse.Config{
|
||||||
File: os.Args[2],
|
File: os.Args[2],
|
||||||
Temp: os.Args[3] == "true",
|
Args: []string{},
|
||||||
Args: os.Args[4:],
|
IsCpp: true,
|
||||||
|
Temp: false,
|
||||||
}
|
}
|
||||||
if !cfg.Temp {
|
|
||||||
absPath, err := filepath.Abs(cfg.File)
|
for i := 3; i < len(os.Args); i++ {
|
||||||
check(err)
|
arg := os.Args[i]
|
||||||
cfg.File = absPath
|
switch {
|
||||||
println(cfg.File)
|
case strings.HasPrefix(arg, "-temp="):
|
||||||
|
cfg.Temp = parseBoolArg(arg, "temp", false)
|
||||||
|
os.Args = append(os.Args[:i], os.Args[i+1:]...)
|
||||||
|
i--
|
||||||
|
case strings.HasPrefix(arg, "-cpp="):
|
||||||
|
cfg.IsCpp = parseBoolArg(arg, "cpp", true)
|
||||||
|
os.Args = append(os.Args[:i], os.Args[i+1:]...)
|
||||||
|
i--
|
||||||
|
default:
|
||||||
|
cfg.Args = append(cfg.Args, arg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
converter, err := parse.NewConverter(cfg)
|
converter, err := parse.NewConverter(cfg)
|
||||||
@@ -151,3 +168,17 @@ func outputInfo(context *parse.Context) {
|
|||||||
defer info.Delete()
|
defer info.Delete()
|
||||||
c.Printf(str)
|
c.Printf(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseBoolArg(arg, name string, defaultValue bool) bool {
|
||||||
|
parts := strings.SplitN(arg, "=", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
fmt.Printf("Warning: Invalid -%s= argument, defaulting to %v\n", name, defaultValue)
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
value, err := strconv.ParseBool(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Warning: Invalid -%s= value '%s', defaulting to %v\n", name, parts[1], defaultValue)
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ var tagMap = map[string]ast.Tag{
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
File string
|
File string
|
||||||
Temp bool
|
Temp bool
|
||||||
Args []string
|
Args []string
|
||||||
|
IsCpp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConverter(config *Config) (*Converter, error) {
|
func NewConverter(config *Config) (*Converter, error) {
|
||||||
@@ -72,12 +73,16 @@ func NewConverter(config *Config) (*Converter, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) {
|
func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) {
|
||||||
if config.Args == nil || len(config.Args) == 0 {
|
// default use the c/c++ standard of clang; c:gnu17 c++:gnu++17
|
||||||
config.Args = []string{"-x", "c++", "-std=c++11"}
|
// https://clang.llvm.org/docs/CommandGuide/clang.html
|
||||||
|
defaultArgs := []string{"-x", "c"}
|
||||||
|
if config.IsCpp {
|
||||||
|
defaultArgs = []string{"-x", "c++"}
|
||||||
}
|
}
|
||||||
|
allArgs := append(defaultArgs, config.Args...)
|
||||||
|
|
||||||
cArgs := make([]*c.Char, len(config.Args))
|
cArgs := make([]*c.Char, len(allArgs))
|
||||||
for i, arg := range config.Args {
|
for i, arg := range allArgs {
|
||||||
cArgs[i] = c.AllocaCStr(arg)
|
cArgs[i] = c.AllocaCStr(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,6 +423,7 @@ func (ct *Converter) GenerateAnonymousName(cursor clang.Cursor) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// converts functions, methods, constructors, destructors (including out-of-class decl) to ast.FuncDecl nodes.
|
// converts functions, methods, constructors, destructors (including out-of-class decl) to ast.FuncDecl nodes.
|
||||||
|
// todo(zzy): manglename (c++)
|
||||||
func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
|
func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
|
||||||
name := cursor.String()
|
name := cursor.String()
|
||||||
defer name.Dispose()
|
defer name.Dispose()
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ import (
|
|||||||
func RunTest(testName string, testCases []string) {
|
func RunTest(testName string, testCases []string) {
|
||||||
for i, content := range testCases {
|
for i, content := range testCases {
|
||||||
converter, err := parse.NewConverter(&parse.Config{
|
converter, err := parse.NewConverter(&parse.Config{
|
||||||
File: content,
|
File: content,
|
||||||
Temp: true,
|
Temp: true,
|
||||||
|
IsCpp: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -45,9 +46,16 @@ type GetTypeOptions struct {
|
|||||||
ExpectTypeKind clang.TypeKind
|
ExpectTypeKind clang.TypeKind
|
||||||
|
|
||||||
// Args contains additional compilation arguments passed to Clang (optional)
|
// Args contains additional compilation arguments passed to Clang (optional)
|
||||||
// Default is []string{"-x", "c++", "-std=c++11"}
|
// These are appended after the default language-specific arguments
|
||||||
// *For complex C types, C language args Must be specified, e.g., []string{"-x", "c", "-std=c99"}
|
// Example: []string{"-std=c++11"}
|
||||||
Args []string
|
Args []string
|
||||||
|
|
||||||
|
// IsCpp indicates whether the code should be treated as C++ (true) or C (false)
|
||||||
|
// This affects the default language arguments passed to Clang:
|
||||||
|
// - For C++: []string{"-x", "c++"}
|
||||||
|
// - For C: []string{"-x", "c"}
|
||||||
|
// *For complex C types, C Must be specified
|
||||||
|
IsCpp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetType returns the clang.Type of the given type code
|
// GetType returns the clang.Type of the given type code
|
||||||
@@ -56,9 +64,10 @@ type GetTypeOptions struct {
|
|||||||
func GetType(option *GetTypeOptions) (clang.Type, *clang.Index, *clang.TranslationUnit) {
|
func GetType(option *GetTypeOptions) (clang.Type, *clang.Index, *clang.TranslationUnit) {
|
||||||
code := fmt.Sprintf("%s placeholder;", option.TypeCode)
|
code := fmt.Sprintf("%s placeholder;", option.TypeCode)
|
||||||
index, unit, err := parse.CreateTranslationUnit(&parse.Config{
|
index, unit, err := parse.CreateTranslationUnit(&parse.Config{
|
||||||
File: code,
|
File: code,
|
||||||
Temp: true,
|
Temp: true,
|
||||||
Args: option.Args,
|
Args: option.Args,
|
||||||
|
IsCpp: option.IsCpp,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ func TestNonBuiltinTypes() {
|
|||||||
for _, t := range tests {
|
for _, t := range tests {
|
||||||
typ, index, unit := test.GetType(&test.GetTypeOptions{
|
typ, index, unit := test.GetType(&test.GetTypeOptions{
|
||||||
TypeCode: t,
|
TypeCode: t,
|
||||||
|
IsCpp: true,
|
||||||
})
|
})
|
||||||
converter := &parse.Converter{}
|
converter := &parse.Converter{}
|
||||||
expr := converter.ProcessType(typ)
|
expr := converter.ProcessType(typ)
|
||||||
@@ -167,7 +168,7 @@ func getComplexType(flag ast.TypeFlag) clang.Type {
|
|||||||
typ, _, _ := test.GetType(&test.GetTypeOptions{
|
typ, _, _ := test.GetType(&test.GetTypeOptions{
|
||||||
TypeCode: code,
|
TypeCode: code,
|
||||||
ExpectTypeKind: clang.TypeComplex,
|
ExpectTypeKind: clang.TypeComplex,
|
||||||
Args: []string{"-x", "c", "-std=c99"},
|
IsCpp: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
return typ
|
return typ
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import (
|
|||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
Files map[string]*ast.File
|
Files map[string]*ast.File
|
||||||
|
IsCpp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContext() *Context {
|
func NewContext(isCpp bool) *Context {
|
||||||
return &Context{
|
return &Context{
|
||||||
Files: make(map[string]*ast.File),
|
Files: make(map[string]*ast.File),
|
||||||
|
IsCpp: isCpp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,8 +62,9 @@ func (p *Context) processFile(path string) error {
|
|||||||
|
|
||||||
func (p *Context) parseFile(path string) (map[string]*ast.File, error) {
|
func (p *Context) parseFile(path string) (map[string]*ast.File, error) {
|
||||||
converter, err := NewConverter(&Config{
|
converter, err := NewConverter(&Config{
|
||||||
File: path,
|
File: path,
|
||||||
Temp: false,
|
Temp: false,
|
||||||
|
IsCpp: p.IsCpp,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create converter " + path)
|
return nil, errors.New("failed to create converter " + path)
|
||||||
|
|||||||
Reference in New Issue
Block a user