mv llcppsigfetch,llcppsymg => github.com/goplus/llcppg
This commit is contained in:
@@ -1,273 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/args"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
ags, remainArgs := args.ParseArgs(os.Args[1:], map[string]bool{
|
|
||||||
"--extract": true,
|
|
||||||
})
|
|
||||||
|
|
||||||
if ags.Help {
|
|
||||||
printUsage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if ags.Verbose {
|
|
||||||
parse.SetDebug(parse.DbgFlagAll)
|
|
||||||
}
|
|
||||||
extract := false
|
|
||||||
out := false
|
|
||||||
|
|
||||||
var extractFile string
|
|
||||||
isTemp := false
|
|
||||||
isCpp := true
|
|
||||||
otherArgs := []string{}
|
|
||||||
|
|
||||||
for i := 0; i < len(remainArgs); i++ {
|
|
||||||
arg := remainArgs[i]
|
|
||||||
switch {
|
|
||||||
case arg == "--extract":
|
|
||||||
extract = true
|
|
||||||
if i+1 < len(remainArgs) && !strings.HasPrefix(remainArgs[i+1], "-") {
|
|
||||||
extractFile = remainArgs[i+1]
|
|
||||||
i++
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error: --extract requires a valid file argument")
|
|
||||||
printUsage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
case strings.HasPrefix(arg, "-out="):
|
|
||||||
out = parseBoolArg(arg, "out", false)
|
|
||||||
case strings.HasPrefix(arg, "-temp="):
|
|
||||||
isTemp = parseBoolArg(arg, "temp", false)
|
|
||||||
case strings.HasPrefix(arg, "-cpp="):
|
|
||||||
isCpp = parseBoolArg(arg, "cpp", true)
|
|
||||||
default:
|
|
||||||
otherArgs = append(otherArgs, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if extract {
|
|
||||||
if ags.Verbose {
|
|
||||||
fmt.Fprintln(os.Stderr, "runExtract: extractFile:", extractFile)
|
|
||||||
fmt.Fprintln(os.Stderr, "isTemp:", isTemp)
|
|
||||||
fmt.Fprintln(os.Stderr, "isCpp:", isCpp)
|
|
||||||
fmt.Fprintln(os.Stderr, "out:", out)
|
|
||||||
fmt.Fprintln(os.Stderr, "otherArgs:", otherArgs)
|
|
||||||
}
|
|
||||||
runExtract(extractFile, isTemp, isCpp, out, otherArgs, ags.Verbose)
|
|
||||||
} else {
|
|
||||||
if ags.Verbose {
|
|
||||||
fmt.Fprintln(os.Stderr, "runFromConfig: config file:", ags.CfgFile)
|
|
||||||
fmt.Fprintln(os.Stderr, "use stdin:", ags.UseStdin)
|
|
||||||
fmt.Fprintln(os.Stderr, "output to file:", out)
|
|
||||||
}
|
|
||||||
runFromConfig(ags.CfgFile, ags.UseStdin, out, ags.Verbose)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func printUsage() {
|
|
||||||
fmt.Println("Usage:")
|
|
||||||
fmt.Println(" llcppsigfetch [<config_file>] [-out=<bool>]")
|
|
||||||
fmt.Println(" OR")
|
|
||||||
fmt.Println(" llcppsigfetch --extract <file> [-out=<bool>] [-temp=<bool>] [-cpp=<bool>] [args...]")
|
|
||||||
fmt.Println("")
|
|
||||||
fmt.Println("Options:")
|
|
||||||
fmt.Println(" [<config_file>]: Path to the configuration file (use '-' for stdin)")
|
|
||||||
fmt.Println(" If not provided, uses default 'llcppg.cfg'")
|
|
||||||
fmt.Println(" -out=<bool>: Optional. Set to 'true' to output results to a file,")
|
|
||||||
fmt.Println(" 'false' (default) to output to stdout")
|
|
||||||
fmt.Println(" This option can be used with both modes")
|
|
||||||
fmt.Println("")
|
|
||||||
fmt.Println(" --extract: Extract information from a single file")
|
|
||||||
fmt.Println(" <file>: Path to the file to process, or file content if -temp=true")
|
|
||||||
fmt.Println(" -temp=<bool>: Optional. Set to 'true' if <file> contains file content,")
|
|
||||||
fmt.Println(" 'false' (default) if it's a file path")
|
|
||||||
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(" --help, -h: Show this help message")
|
|
||||||
fmt.Println("")
|
|
||||||
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, verbose bool) {
|
|
||||||
var data []byte
|
|
||||||
var err error
|
|
||||||
if useStdin {
|
|
||||||
data, err = io.ReadAll(os.Stdin)
|
|
||||||
} else {
|
|
||||||
data, err = os.ReadFile(cfgFile)
|
|
||||||
}
|
|
||||||
if verbose {
|
|
||||||
if useStdin {
|
|
||||||
fmt.Fprintln(os.Stderr, "runFromConfig: read from stdin")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(os.Stderr, "runFromConfig: read from file", cfgFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
conf, err := config.GetConf(data)
|
|
||||||
check(err)
|
|
||||||
defer conf.Delete()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Failed to parse config file:", cfgFile)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo(zzy): reuse the llcppsymg's cflags parse
|
|
||||||
cflag := ParseCFlags(conf.CFlags)
|
|
||||||
files, notFounds, err := cflag.GenHeaderFilePaths(conf.Include)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
fmt.Fprintln(os.Stderr, "runFromConfig: header file paths", files)
|
|
||||||
if len(notFounds) > 0 {
|
|
||||||
fmt.Fprintln(os.Stderr, "runFromConfig: not found header files", notFounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context := parse.NewContext(conf.Cplusplus)
|
|
||||||
err = context.ProcessFiles(files)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
outputInfo(context, outputToFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func runExtract(file string, isTemp bool, isCpp bool, outToFile bool, otherArgs []string, verbose bool) {
|
|
||||||
cfg := &clangutils.Config{
|
|
||||||
File: file,
|
|
||||||
Args: otherArgs,
|
|
||||||
IsCpp: isCpp,
|
|
||||||
Temp: isTemp,
|
|
||||||
}
|
|
||||||
converter, err := parse.NewConverter(cfg)
|
|
||||||
check(err)
|
|
||||||
_, err = converter.Convert()
|
|
||||||
check(err)
|
|
||||||
result := converter.MarshalOutputASTFiles()
|
|
||||||
cstr := result.Print()
|
|
||||||
outputResult(cstr, outToFile)
|
|
||||||
cjson.FreeCStr(cstr)
|
|
||||||
result.Delete()
|
|
||||||
converter.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
func check(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func outputResult(result *c.Char, outputToFile bool) {
|
|
||||||
if outputToFile {
|
|
||||||
outputFile := "llcppg.sigfetch.json"
|
|
||||||
err := os.WriteFile(outputFile, []byte(c.GoString(result)), 0644)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error writing to output file: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "Results saved to %s\n", outputFile)
|
|
||||||
} else {
|
|
||||||
c.Printf(c.Str("%s"), result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 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) {
|
|
||||||
info := context.Output()
|
|
||||||
str := info.Print()
|
|
||||||
defer cjson.FreeCStr(str)
|
|
||||||
defer info.Delete()
|
|
||||||
outputResult(str, outputToFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseBoolArg(arg, name string, defaultValue bool) bool {
|
|
||||||
parts := strings.SplitN(arg, "=", 2)
|
|
||||||
if len(parts) != 2 {
|
|
||||||
fmt.Fprintf(os.Stderr, "Warning: Invalid -%s= argument, defaulting to %v\n", name, defaultValue)
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
value, err := strconv.ParseBool(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Warning: Invalid -%s= value '%s', defaulting to %v\n", name, parts[1], defaultValue)
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
@@ -1,976 +0,0 @@
|
|||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/ast"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/token"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FileEntry struct {
|
|
||||||
Path string
|
|
||||||
Doc *ast.File
|
|
||||||
}
|
|
||||||
|
|
||||||
type Converter struct {
|
|
||||||
Files []*FileEntry
|
|
||||||
FileOrder []string // todo(zzy): more efficient struct
|
|
||||||
curLoc ast.Location
|
|
||||||
index *clang.Index
|
|
||||||
unit *clang.TranslationUnit
|
|
||||||
|
|
||||||
indent int // for verbose debug
|
|
||||||
}
|
|
||||||
|
|
||||||
var tagMap = map[string]ast.Tag{
|
|
||||||
"struct": ast.Struct,
|
|
||||||
"union": ast.Union,
|
|
||||||
"enum": ast.Enum,
|
|
||||||
"class": ast.Class,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
File string
|
|
||||||
Temp bool
|
|
||||||
Args []string
|
|
||||||
IsCpp bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConverter(config *clangutils.Config) (*Converter, error) {
|
|
||||||
if debugParse {
|
|
||||||
fmt.Fprintln(os.Stderr, "NewConverter: config")
|
|
||||||
fmt.Fprintln(os.Stderr, "config.File", config.File)
|
|
||||||
fmt.Fprintln(os.Stderr, "config.Args", config.Args)
|
|
||||||
fmt.Fprintln(os.Stderr, "config.IsCpp", config.IsCpp)
|
|
||||||
fmt.Fprintln(os.Stderr, "config.Temp", config.Temp)
|
|
||||||
}
|
|
||||||
|
|
||||||
index, unit, err := clangutils.CreateTranslationUnit(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Converter{
|
|
||||||
Files: make([]*FileEntry, 0),
|
|
||||||
index: index,
|
|
||||||
unit: unit,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) Dispose() {
|
|
||||||
ct.logln("Dispose")
|
|
||||||
ct.index.Dispose()
|
|
||||||
ct.unit.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) GetTokens(cursor clang.Cursor) []*ast.Token {
|
|
||||||
ran := cursor.Extent()
|
|
||||||
var numTokens c.Uint
|
|
||||||
var tokens *clang.Token
|
|
||||||
ct.unit.Tokenize(ran, &tokens, &numTokens)
|
|
||||||
defer ct.unit.DisposeTokens(tokens, numTokens)
|
|
||||||
|
|
||||||
tokensSlice := unsafe.Slice(tokens, int(numTokens))
|
|
||||||
|
|
||||||
result := make([]*ast.Token, 0, int(numTokens))
|
|
||||||
for _, tok := range tokensSlice {
|
|
||||||
tokStr := ct.unit.Token(tok)
|
|
||||||
result = append(result, &ast.Token{
|
|
||||||
Token: toToken(tok),
|
|
||||||
Lit: c.GoString(tokStr.CStr()),
|
|
||||||
})
|
|
||||||
tokStr.Dispose()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) logBase() string {
|
|
||||||
return strings.Repeat(" ", ct.indent)
|
|
||||||
}
|
|
||||||
func (ct *Converter) incIndent() {
|
|
||||||
ct.indent++
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) decIndent() {
|
|
||||||
if ct.indent > 0 {
|
|
||||||
ct.indent--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) logf(format string, args ...interface{}) {
|
|
||||||
if debugParse {
|
|
||||||
fmt.Fprintf(os.Stderr, ct.logBase()+format, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (ct *Converter) logln(args ...interface{}) {
|
|
||||||
if debugParse {
|
|
||||||
if len(args) > 0 {
|
|
||||||
firstArg := fmt.Sprintf("%s%v", ct.logBase(), args[0])
|
|
||||||
fmt.Fprintln(os.Stderr, append([]interface{}{firstArg}, args[1:]...)...)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(os.Stderr, ct.logBase())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) UpdateLoc(cursor clang.Cursor) {
|
|
||||||
loc := cursor.Location()
|
|
||||||
var file clang.File
|
|
||||||
loc.SpellingLocation(&file, nil, nil, nil)
|
|
||||||
|
|
||||||
filePath := toStr(file.FileName())
|
|
||||||
|
|
||||||
if filePath == "" {
|
|
||||||
//todo(zzy): For some built-in macros, there is no file.
|
|
||||||
ct.curLoc = ast.Location{File: ""}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ct.curLoc = ast.Location{File: filePath}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) GetCurFile() *ast.File {
|
|
||||||
if ct.curLoc.File == "" {
|
|
||||||
ct.logln("GetCurFile: NO FILE")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// todo(zzy): more efficient
|
|
||||||
for i, entry := range ct.Files {
|
|
||||||
if entry.Path == ct.curLoc.File {
|
|
||||||
ct.logln("GetCurFile: found", ct.curLoc.File)
|
|
||||||
return ct.Files[i].Doc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ct.logln("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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase {
|
|
||||||
base := ast.DeclBase{
|
|
||||||
Loc: &ct.curLoc,
|
|
||||||
Parent: ct.BuildScopingExpr(cursor.SemanticParent()),
|
|
||||||
}
|
|
||||||
commentGroup, isDoc := ct.ParseCommentGroup(cursor)
|
|
||||||
if isDoc {
|
|
||||||
base.Doc = commentGroup
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
|
|
||||||
// extracts and parses comments associated with a given Clang cursor,
|
|
||||||
// distinguishing between documentation comments and line comments.
|
|
||||||
// It uses libclang to parse only Doxygen-style comments.
|
|
||||||
|
|
||||||
// Reference for Doxygen documentation blocks: https://www.doxygen.nl/manual/docblocks.html
|
|
||||||
|
|
||||||
// The function determines whether a comment is a documentation comment or a line comment by
|
|
||||||
// comparing the range of the comment node with the range of the declaration node in the AST.
|
|
||||||
|
|
||||||
// Note: In cases where both documentation comments and line comments conceptually exist,
|
|
||||||
// only the line comment will be preserved.
|
|
||||||
func (ct *Converter) ParseCommentGroup(cursor clang.Cursor) (comentGroup *ast.CommentGroup, isDoc bool) {
|
|
||||||
rawComment := toStr(cursor.RawCommentText())
|
|
||||||
commentGroup := &ast.CommentGroup{}
|
|
||||||
if rawComment != "" {
|
|
||||||
commentRange := cursor.CommentRange()
|
|
||||||
cursorRange := cursor.Extent()
|
|
||||||
isDoc := getOffset(commentRange.RangeStart()) < getOffset(cursorRange.RangeStart())
|
|
||||||
commentGroup = ct.ParseComment(rawComment)
|
|
||||||
if len(commentGroup.List) > 0 {
|
|
||||||
return commentGroup, isDoc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ParseComment(rawComment string) *ast.CommentGroup {
|
|
||||||
lines := strings.Split(rawComment, "\n")
|
|
||||||
commentGroup := &ast.CommentGroup{}
|
|
||||||
for _, line := range lines {
|
|
||||||
commentGroup.List = append(commentGroup.List, &ast.Comment{Text: line + "\n"})
|
|
||||||
}
|
|
||||||
return commentGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
// visit top decls (struct,class,function,enum & macro,include)
|
|
||||||
func (ct *Converter) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
|
|
||||||
ct.UpdateLoc(cursor)
|
|
||||||
|
|
||||||
curFile := ct.GetCurFile()
|
|
||||||
|
|
||||||
name := toStr(cursor.String())
|
|
||||||
ct.logf("visitTop: Cursor: %s\n", name)
|
|
||||||
|
|
||||||
if curFile == nil {
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch cursor.Kind {
|
|
||||||
case clang.CursorInclusionDirective:
|
|
||||||
include := ct.ProcessInclude(cursor)
|
|
||||||
curFile.Includes = append(curFile.Includes, include)
|
|
||||||
ct.logln("visitTop: ProcessInclude END ", include.Path)
|
|
||||||
case clang.CursorMacroDefinition:
|
|
||||||
macro := ct.ProcessMacro(cursor)
|
|
||||||
curFile.Macros = append(curFile.Macros, macro)
|
|
||||||
ct.logln("visitTop: ProcessMacro END ", macro.Name, "Tokens Length:", len(macro.Tokens))
|
|
||||||
case clang.CursorEnumDecl:
|
|
||||||
enum := ct.ProcessEnumDecl(cursor)
|
|
||||||
curFile.Decls = append(curFile.Decls, enum)
|
|
||||||
|
|
||||||
ct.logf("visitTop: ProcessEnumDecl END")
|
|
||||||
if enum.Name != nil {
|
|
||||||
ct.logln(enum.Name.Name)
|
|
||||||
} else {
|
|
||||||
ct.logln("ANONY")
|
|
||||||
}
|
|
||||||
|
|
||||||
case clang.CursorClassDecl:
|
|
||||||
classDecl := ct.ProcessClassDecl(cursor)
|
|
||||||
curFile.Decls = append(curFile.Decls, classDecl)
|
|
||||||
// class havent anonymous situation
|
|
||||||
ct.logln("visitTop: ProcessClassDecl END", classDecl.Name.Name)
|
|
||||||
case clang.CursorStructDecl:
|
|
||||||
structDecl := ct.ProcessStructDecl(cursor)
|
|
||||||
curFile.Decls = append(curFile.Decls, structDecl)
|
|
||||||
|
|
||||||
ct.logf("visitTop: ProcessStructDecl END")
|
|
||||||
if structDecl.Name != nil {
|
|
||||||
ct.logln(structDecl.Name.Name)
|
|
||||||
} else {
|
|
||||||
ct.logln("ANONY")
|
|
||||||
}
|
|
||||||
case clang.CursorUnionDecl:
|
|
||||||
unionDecl := ct.ProcessUnionDecl(cursor)
|
|
||||||
curFile.Decls = append(curFile.Decls, unionDecl)
|
|
||||||
|
|
||||||
ct.logf("visitTop: ProcessUnionDecl END")
|
|
||||||
if unionDecl.Name != nil {
|
|
||||||
ct.logln(unionDecl.Name.Name)
|
|
||||||
} else {
|
|
||||||
ct.logln("ANONY")
|
|
||||||
}
|
|
||||||
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
|
|
||||||
funcDecl := ct.ProcessFuncDecl(cursor)
|
|
||||||
curFile.Decls = append(curFile.Decls, funcDecl)
|
|
||||||
ct.logln("visitTop: ProcessFuncDecl END", funcDecl.Name.Name, funcDecl.MangledName, "isStatic:", funcDecl.IsStatic, "isInline:", funcDecl.IsInline)
|
|
||||||
case clang.CursorTypedefDecl:
|
|
||||||
typedefDecl := ct.ProcessTypeDefDecl(cursor)
|
|
||||||
if typedefDecl == nil {
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
}
|
|
||||||
curFile.Decls = append(curFile.Decls, typedefDecl)
|
|
||||||
ct.logln("visitTop: ProcessTypeDefDecl END", typedefDecl.Name.Name)
|
|
||||||
case clang.CursorNamespace:
|
|
||||||
VisitChildren(cursor, ct.visitTop)
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) Convert() ([]*FileEntry, error) {
|
|
||||||
cursor := ct.unit.Cursor()
|
|
||||||
// visit top decls (struct,class,function & macro,include)
|
|
||||||
VisitChildren(cursor, ct.visitTop)
|
|
||||||
return ct.Files, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Visitor func(cursor, parent clang.Cursor) clang.ChildVisitResult
|
|
||||||
|
|
||||||
func VisitChildren(cursor clang.Cursor, fn Visitor) c.Uint {
|
|
||||||
return clang.VisitChildren(cursor, func(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
|
|
||||||
cfn := *(*Visitor)(clientData)
|
|
||||||
return cfn(cursor, parent)
|
|
||||||
}, unsafe.Pointer(&fn))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessType(t clang.Type) ast.Expr {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
|
|
||||||
typeName, typeKind := getTypeDesc(t)
|
|
||||||
ct.logln("ProcessType: TypeName:", typeName, "TypeKind:", typeKind)
|
|
||||||
|
|
||||||
if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin {
|
|
||||||
return ct.ProcessBuiltinType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.Kind == clang.TypeElaborated {
|
|
||||||
return ct.ProcessElaboratedType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.Kind == clang.TypeTypedef {
|
|
||||||
return ct.ProcessTypeDefType(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
var expr ast.Expr
|
|
||||||
switch t.Kind {
|
|
||||||
case clang.TypePointer:
|
|
||||||
name, kind := getTypeDesc(t.PointeeType())
|
|
||||||
ct.logln("ProcessType: PointerType Pointee TypeName:", name, "TypeKind:", kind)
|
|
||||||
expr = &ast.PointerType{X: ct.ProcessType(t.PointeeType())}
|
|
||||||
case clang.TypeLValueReference:
|
|
||||||
name, kind := getTypeDesc(t.NonReferenceType())
|
|
||||||
ct.logln("ProcessType: LvalueRefType NonReference TypeName:", name, "TypeKind:", kind)
|
|
||||||
expr = &ast.LvalueRefType{X: ct.ProcessType(t.NonReferenceType())}
|
|
||||||
case clang.TypeRValueReference:
|
|
||||||
name, kind := getTypeDesc(t.NonReferenceType())
|
|
||||||
ct.logln("ProcessType: RvalueRefType NonReference TypeName:", name, "TypeKind:", kind)
|
|
||||||
expr = &ast.RvalueRefType{X: ct.ProcessType(t.NonReferenceType())}
|
|
||||||
case clang.TypeFunctionProto, clang.TypeFunctionNoProto:
|
|
||||||
// treating TypeFunctionNoProto as a general function without parameters
|
|
||||||
// function type will only collect return type, params will be collected in ProcessFuncDecl
|
|
||||||
name, kind := getTypeDesc(t)
|
|
||||||
ct.logln("ProcessType: FunctionType TypeName:", name, "TypeKind:", kind)
|
|
||||||
expr = ct.ProcessFunctionType(t)
|
|
||||||
case clang.TypeConstantArray, clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray:
|
|
||||||
if t.Kind == clang.TypeConstantArray {
|
|
||||||
len := (*c.Char)(c.Malloc(unsafe.Sizeof(c.Char(0)) * 20))
|
|
||||||
c.Sprintf(len, c.Str("%lld"), t.ArraySize())
|
|
||||||
defer c.Free(unsafe.Pointer(len))
|
|
||||||
expr = &ast.ArrayType{
|
|
||||||
Elt: ct.ProcessType(t.ArrayElementType()),
|
|
||||||
Len: &ast.BasicLit{Kind: ast.IntLit, Value: c.GoString(len)},
|
|
||||||
}
|
|
||||||
} else if t.Kind == clang.TypeIncompleteArray {
|
|
||||||
// incomplete array havent len expr
|
|
||||||
expr = &ast.ArrayType{
|
|
||||||
Elt: ct.ProcessType(t.ArrayElementType()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
name, kind := getTypeDesc(t)
|
|
||||||
ct.logln("ProcessType: Unknown Type TypeName:", name, "TypeKind:", kind)
|
|
||||||
}
|
|
||||||
return expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// For function types, we can only obtain the parameter types, but not the parameter names.
|
|
||||||
// This is because we cannot reverse-lookup the corresponding declaration node from a function type.
|
|
||||||
// Note: For function declarations, parameter names are collected in the ProcessFuncDecl method.
|
|
||||||
func (ct *Converter) ProcessFunctionType(t clang.Type) *ast.FuncType {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
typeName, typeKind := getTypeDesc(t)
|
|
||||||
ct.logln("ProcessFunctionType: TypeName:", typeName, "TypeKind:", typeKind)
|
|
||||||
// Note: Attempting to get the type declaration for a function type will result in CursorNoDeclFound
|
|
||||||
// cursor := t.TypeDeclaration()
|
|
||||||
// This would return CursorNoDeclFound
|
|
||||||
resType := t.ResultType()
|
|
||||||
|
|
||||||
name, kind := getTypeDesc(resType)
|
|
||||||
ct.logln("ProcessFunctionType: ResultType TypeName:", name, "TypeKind:", kind)
|
|
||||||
|
|
||||||
ret := ct.ProcessType(resType)
|
|
||||||
params := &ast.FieldList{}
|
|
||||||
numArgs := t.NumArgTypes()
|
|
||||||
for i := 0; i < int(numArgs); i++ {
|
|
||||||
argType := t.ArgType(c.Uint(i))
|
|
||||||
params.List = append(params.List, &ast.Field{
|
|
||||||
Type: ct.ProcessType(argType),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if t.IsFunctionTypeVariadic() != 0 {
|
|
||||||
params.List = append(params.List, &ast.Field{
|
|
||||||
Type: &ast.Variadic{},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ast.FuncType{
|
|
||||||
Ret: ret,
|
|
||||||
Params: params,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
name, kind := getCursorDesc(cursor)
|
|
||||||
ct.logln("ProcessTypeDefDecl: CursorName:", name, "CursorKind:", kind, "CursorTypeKind:", toStr(cursor.Type().Kind.String()))
|
|
||||||
|
|
||||||
typ := ct.ProcessUnderlyingType(cursor)
|
|
||||||
// For cases like: typedef struct { int x; } Name;
|
|
||||||
// libclang incorrectly reports the anonymous structure as a named structure
|
|
||||||
// with the same name as the typedef. Since the anonymous structure definition
|
|
||||||
// has already been collected when processing its declaration cursor,
|
|
||||||
// we skip this redundant typedef declaration by returning nil.
|
|
||||||
if typ == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
decl := &ast.TypedefDecl{
|
|
||||||
DeclBase: ct.CreateDeclBase(cursor),
|
|
||||||
Name: &ast.Ident{Name: name},
|
|
||||||
Type: typ,
|
|
||||||
}
|
|
||||||
return decl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessUnderlyingType(cursor clang.Cursor) ast.Expr {
|
|
||||||
underlyingTyp := cursor.TypedefDeclUnderlyingType()
|
|
||||||
|
|
||||||
if underlyingTyp.Kind != clang.TypeElaborated {
|
|
||||||
ct.logln("ProcessUnderlyingType: not elaborated")
|
|
||||||
return ct.ProcessType(underlyingTyp)
|
|
||||||
}
|
|
||||||
|
|
||||||
referTypeCursor := underlyingTyp.TypeDeclaration()
|
|
||||||
if toStr(cursor.String()) == toStr(referTypeCursor.String()) && isCursorChildOf(referTypeCursor, cursor) {
|
|
||||||
ct.logln("ProcessUnderlyingType: is self reference")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return ct.ProcessElaboratedType(underlyingTyp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// converts functions, methods, constructors, destructors (including out-of-class decl) to ast.FuncDecl nodes.
|
|
||||||
func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
name, kind := getCursorDesc(cursor)
|
|
||||||
mangledName := toStr(cursor.Mangling())
|
|
||||||
ct.logln("ProcessFuncDecl: CursorName:", name, "CursorKind:", kind)
|
|
||||||
|
|
||||||
// function type will only collect return type
|
|
||||||
// ProcessType can't get the field names,will collect in follows
|
|
||||||
funcType, ok := ct.ProcessType(cursor.Type()).(*ast.FuncType)
|
|
||||||
if !ok {
|
|
||||||
ct.logln("ProcessFuncDecl: failed to process function type")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ct.logln("ProcessFuncDecl: ProcessFieldList")
|
|
||||||
params := ct.ProcessFieldList(cursor)
|
|
||||||
funcType.Params = params
|
|
||||||
|
|
||||||
// Linux has one less leading underscore than macOS, so remove one leading underscore on macOS
|
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
mangledName = strings.TrimPrefix(mangledName, "_")
|
|
||||||
}
|
|
||||||
|
|
||||||
funcDecl := &ast.FuncDecl{
|
|
||||||
DeclBase: ct.CreateDeclBase(cursor),
|
|
||||||
Name: &ast.Ident{Name: name},
|
|
||||||
Type: funcType,
|
|
||||||
MangledName: mangledName,
|
|
||||||
}
|
|
||||||
|
|
||||||
if cursor.IsFunctionInlined() != 0 {
|
|
||||||
funcDecl.IsInline = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if isMethod(cursor) {
|
|
||||||
ct.logln("ProcessFuncDecl: is method, ProcessMethodAttributes")
|
|
||||||
ct.ProcessMethodAttributes(cursor, funcDecl)
|
|
||||||
} else {
|
|
||||||
if cursor.StorageClass() == clang.SCStatic {
|
|
||||||
funcDecl.IsStatic = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return funcDecl
|
|
||||||
}
|
|
||||||
|
|
||||||
// get Methods Attributes
|
|
||||||
func (ct *Converter) ProcessMethodAttributes(cursor clang.Cursor, fn *ast.FuncDecl) {
|
|
||||||
if parent := cursor.SemanticParent(); parent.Equal(cursor.LexicalParent()) != 1 {
|
|
||||||
fn.DeclBase.Parent = ct.BuildScopingExpr(cursor.SemanticParent())
|
|
||||||
}
|
|
||||||
|
|
||||||
switch cursor.Kind {
|
|
||||||
case clang.CursorDestructor:
|
|
||||||
fn.IsDestructor = true
|
|
||||||
case clang.CursorConstructor:
|
|
||||||
fn.IsConstructor = true
|
|
||||||
if cursor.IsExplicit() != 0 {
|
|
||||||
fn.IsExplicit = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if cursor.IsStatic() != 0 {
|
|
||||||
fn.IsStatic = true
|
|
||||||
}
|
|
||||||
if cursor.IsVirtual() != 0 || cursor.IsPureVirtual() != 0 {
|
|
||||||
fn.IsVirtual = true
|
|
||||||
}
|
|
||||||
if cursor.IsConst() != 0 {
|
|
||||||
fn.IsConst = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var numOverridden c.Uint
|
|
||||||
var overridden *clang.Cursor
|
|
||||||
cursor.OverriddenCursors(&overridden, &numOverridden)
|
|
||||||
if numOverridden > 0 {
|
|
||||||
fn.IsOverride = true
|
|
||||||
}
|
|
||||||
overridden.DisposeOverriddenCursors()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessEnumType(cursor clang.Cursor) *ast.EnumType {
|
|
||||||
items := make([]*ast.EnumItem, 0)
|
|
||||||
|
|
||||||
VisitChildren(cursor, func(cursor, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
if cursor.Kind == clang.CursorEnumConstantDecl {
|
|
||||||
name := cursor.String()
|
|
||||||
defer name.Dispose()
|
|
||||||
|
|
||||||
val := (*c.Char)(c.Malloc(unsafe.Sizeof(c.Char(0)) * 20))
|
|
||||||
c.Sprintf(val, c.Str("%lld"), cursor.EnumConstantDeclValue())
|
|
||||||
defer c.Free(unsafe.Pointer(val))
|
|
||||||
|
|
||||||
enum := &ast.EnumItem{
|
|
||||||
Name: &ast.Ident{Name: c.GoString(name.CStr())},
|
|
||||||
Value: &ast.BasicLit{
|
|
||||||
Kind: ast.IntLit,
|
|
||||||
Value: c.GoString(val),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
items = append(items, enum)
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
})
|
|
||||||
|
|
||||||
return &ast.EnumType{
|
|
||||||
Items: items,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessEnumDecl(cursor clang.Cursor) *ast.EnumTypeDecl {
|
|
||||||
cursorName, cursorKind := getCursorDesc(cursor)
|
|
||||||
ct.logln("ProcessEnumDecl: CursorName:", cursorName, "CursorKind:", cursorKind)
|
|
||||||
|
|
||||||
decl := &ast.EnumTypeDecl{
|
|
||||||
DeclBase: ct.CreateDeclBase(cursor),
|
|
||||||
Type: ct.ProcessEnumType(cursor),
|
|
||||||
}
|
|
||||||
|
|
||||||
anony := cursor.IsAnonymous()
|
|
||||||
if anony == 0 {
|
|
||||||
decl.Name = &ast.Ident{Name: cursorName}
|
|
||||||
ct.logln("ProcessEnumDecl: has name", cursorName)
|
|
||||||
} else {
|
|
||||||
ct.logln("ProcessRecordDecl: is anonymous")
|
|
||||||
}
|
|
||||||
|
|
||||||
return decl
|
|
||||||
}
|
|
||||||
|
|
||||||
// current only collect macro which defined in file
|
|
||||||
func (ct *Converter) ProcessMacro(cursor clang.Cursor) *ast.Macro {
|
|
||||||
name := toStr(cursor.String())
|
|
||||||
|
|
||||||
macro := &ast.Macro{
|
|
||||||
Name: name,
|
|
||||||
Tokens: ct.GetTokens(cursor),
|
|
||||||
}
|
|
||||||
return macro
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessInclude(cursor clang.Cursor) *ast.Include {
|
|
||||||
name := toStr(cursor.String())
|
|
||||||
return &ast.Include{Path: name}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) createBaseField(cursor clang.Cursor) *ast.Field {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
|
|
||||||
fieldName := toStr(cursor.String())
|
|
||||||
|
|
||||||
typ := cursor.Type()
|
|
||||||
typeName, typeKind := getTypeDesc(typ)
|
|
||||||
|
|
||||||
ct.logf("createBaseField: ProcessType %s TypeKind: %s", typeName, typeKind)
|
|
||||||
|
|
||||||
field := &ast.Field{
|
|
||||||
Type: ct.ProcessType(typ),
|
|
||||||
}
|
|
||||||
|
|
||||||
commentGroup, isDoc := ct.ParseCommentGroup(cursor)
|
|
||||||
if commentGroup != nil {
|
|
||||||
if isDoc {
|
|
||||||
field.Doc = commentGroup
|
|
||||||
} else {
|
|
||||||
field.Comment = commentGroup
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if fieldName != "" {
|
|
||||||
field.Names = []*ast.Ident{{Name: fieldName}}
|
|
||||||
}
|
|
||||||
return field
|
|
||||||
}
|
|
||||||
|
|
||||||
// For Record Type(struct,union ...) & Func 's FieldList
|
|
||||||
func (ct *Converter) ProcessFieldList(cursor clang.Cursor) *ast.FieldList {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
|
|
||||||
params := &ast.FieldList{}
|
|
||||||
ct.logln("ProcessFieldList: VisitChildren")
|
|
||||||
VisitChildren(cursor, func(subcsr, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
switch subcsr.Kind {
|
|
||||||
case clang.CursorParmDecl, clang.CursorFieldDecl:
|
|
||||||
// In C language, parameter lists do not have similar parameter grouping in Go.
|
|
||||||
// func foo(a, b int)
|
|
||||||
|
|
||||||
// For follows struct, it will also parse to two FieldDecl
|
|
||||||
// struct A {
|
|
||||||
// int a, b;
|
|
||||||
// };
|
|
||||||
if subcsr.Kind == clang.CursorFieldDecl {
|
|
||||||
ct.logln("ProcessFieldList: CursorFieldDecl")
|
|
||||||
} else {
|
|
||||||
ct.logln("ProcessFieldList: CursorParmDecl")
|
|
||||||
}
|
|
||||||
|
|
||||||
field := ct.createBaseField(subcsr)
|
|
||||||
if subcsr.Kind == clang.CursorFieldDecl {
|
|
||||||
field.Access = ast.AccessSpecifier(subcsr.CXXAccessSpecifier())
|
|
||||||
}
|
|
||||||
|
|
||||||
params.List = append(params.List, field)
|
|
||||||
|
|
||||||
case clang.CursorVarDecl:
|
|
||||||
if subcsr.StorageClass() == clang.SCStatic {
|
|
||||||
// static member variable
|
|
||||||
field := ct.createBaseField(subcsr)
|
|
||||||
field.Access = ast.AccessSpecifier(subcsr.CXXAccessSpecifier())
|
|
||||||
field.IsStatic = true
|
|
||||||
params.List = append(params.List, field)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
})
|
|
||||||
|
|
||||||
if (cursor.Kind == clang.CursorFunctionDecl || isMethod(cursor)) && cursor.IsVariadic() != 0 {
|
|
||||||
params.List = append(params.List, &ast.Field{
|
|
||||||
Type: &ast.Variadic{},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return params
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note:Public Method is considered
|
|
||||||
func (ct *Converter) ProcessMethods(cursor clang.Cursor) []*ast.FuncDecl {
|
|
||||||
methods := make([]*ast.FuncDecl, 0)
|
|
||||||
VisitChildren(cursor, func(subcsr, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
if isMethod(subcsr) && subcsr.CXXAccessSpecifier() == clang.CXXPublic {
|
|
||||||
method := ct.ProcessFuncDecl(subcsr)
|
|
||||||
if method != nil {
|
|
||||||
methods = append(methods, method)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
})
|
|
||||||
return methods
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessRecordDecl(cursor clang.Cursor) *ast.TypeDecl {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
cursorName, cursorKind := getCursorDesc(cursor)
|
|
||||||
ct.logln("ProcessRecordDecl: CursorName:", cursorName, "CursorKind:", cursorKind)
|
|
||||||
|
|
||||||
decl := &ast.TypeDecl{
|
|
||||||
DeclBase: ct.CreateDeclBase(cursor),
|
|
||||||
Type: ct.ProcessRecordType(cursor),
|
|
||||||
}
|
|
||||||
|
|
||||||
anony := cursor.IsAnonymousRecordDecl()
|
|
||||||
if anony == 0 {
|
|
||||||
decl.Name = &ast.Ident{Name: cursorName}
|
|
||||||
ct.logln("ProcessRecordDecl: has name", cursorName)
|
|
||||||
} else {
|
|
||||||
ct.logln("ProcessRecordDecl: is anonymous")
|
|
||||||
}
|
|
||||||
|
|
||||||
return decl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessStructDecl(cursor clang.Cursor) *ast.TypeDecl {
|
|
||||||
return ct.ProcessRecordDecl(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessUnionDecl(cursor clang.Cursor) *ast.TypeDecl {
|
|
||||||
return ct.ProcessRecordDecl(cursor)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessClassDecl(cursor clang.Cursor) *ast.TypeDecl {
|
|
||||||
cursorName, cursorKind := getCursorDesc(cursor)
|
|
||||||
ct.logln("ProcessClassDecl: CursorName:", cursorName, "CursorKind:", cursorKind)
|
|
||||||
|
|
||||||
// Pushing class scope before processing its type and popping after
|
|
||||||
base := ct.CreateDeclBase(cursor)
|
|
||||||
typ := ct.ProcessRecordType(cursor)
|
|
||||||
|
|
||||||
decl := &ast.TypeDecl{
|
|
||||||
DeclBase: base,
|
|
||||||
Name: &ast.Ident{Name: cursorName},
|
|
||||||
Type: typ,
|
|
||||||
}
|
|
||||||
|
|
||||||
return decl
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessRecordType(cursor clang.Cursor) *ast.RecordType {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
|
|
||||||
cursorName, cursorKind := getCursorDesc(cursor)
|
|
||||||
ct.logln("ProcessRecordType: CursorName:", cursorName, "CursorKind:", cursorKind)
|
|
||||||
|
|
||||||
tag := toTag(cursor.Kind)
|
|
||||||
ct.logln("ProcessRecordType: toTag", tag)
|
|
||||||
|
|
||||||
ct.logln("ProcessRecordType: ProcessFieldList")
|
|
||||||
fields := ct.ProcessFieldList(cursor)
|
|
||||||
|
|
||||||
ct.logln("ProcessRecordType: ProcessMethods")
|
|
||||||
methods := ct.ProcessMethods(cursor)
|
|
||||||
|
|
||||||
return &ast.RecordType{
|
|
||||||
Tag: tag,
|
|
||||||
Fields: fields,
|
|
||||||
Methods: methods,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process ElaboratedType Reference
|
|
||||||
//
|
|
||||||
// 1. Named elaborated type references:
|
|
||||||
// - Examples: struct MyStruct, union MyUnion, class MyClass, enum MyEnum
|
|
||||||
// - Handling: Constructed as TagExpr or ScopingExpr references
|
|
||||||
//
|
|
||||||
// 2. Anonymous elaborated type references:
|
|
||||||
// - Examples: struct { int x; int y; }, union { int a; float b; }
|
|
||||||
// - Handling: Retrieve their corresponding concrete types
|
|
||||||
func (ct *Converter) ProcessElaboratedType(t clang.Type) ast.Expr {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
typeName, typeKind := getTypeDesc(t)
|
|
||||||
ct.logln("ProcessElaboratedType: TypeName:", typeName, "TypeKind:", typeKind)
|
|
||||||
|
|
||||||
decl := t.TypeDeclaration()
|
|
||||||
|
|
||||||
if decl.IsAnonymous() != 0 {
|
|
||||||
// anonymous type refer (except anonymous RecordType&EnumType in TypedefDecl)
|
|
||||||
if decl.Kind == clang.CursorEnumDecl {
|
|
||||||
return ct.ProcessEnumType(decl)
|
|
||||||
}
|
|
||||||
return ct.ProcessRecordType(decl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for elaborated type, it could have a tag description
|
|
||||||
// like struct A, union B, class C, enum D
|
|
||||||
parts := strings.SplitN(typeName, " ", 2)
|
|
||||||
if len(parts) == 2 {
|
|
||||||
if tagValue, ok := tagMap[parts[0]]; ok {
|
|
||||||
return &ast.TagExpr{
|
|
||||||
Tag: tagValue,
|
|
||||||
Name: ct.BuildScopingExpr(decl),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ct.BuildScopingExpr(decl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessTypeDefType(t clang.Type) ast.Expr {
|
|
||||||
cursor := t.TypeDeclaration()
|
|
||||||
ct.logln("ProcessTypeDefType: Typedef TypeDeclaration", toStr(cursor.String()), toStr(t.String()))
|
|
||||||
if name := toStr(cursor.String()); name != "" {
|
|
||||||
return &ast.Ident{Name: name}
|
|
||||||
}
|
|
||||||
ct.logln("ProcessTypeDefType: typedef type have no name")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) ProcessBuiltinType(t clang.Type) *ast.BuiltinType {
|
|
||||||
ct.incIndent()
|
|
||||||
defer ct.decIndent()
|
|
||||||
typeName, typeKind := getTypeDesc(t)
|
|
||||||
ct.logln("ProcessBuiltinType: TypeName:", typeName, "TypeKind:", typeKind)
|
|
||||||
|
|
||||||
kind := ast.Void
|
|
||||||
var flags ast.TypeFlag
|
|
||||||
|
|
||||||
switch t.Kind {
|
|
||||||
case clang.TypeVoid:
|
|
||||||
kind = ast.Void
|
|
||||||
case clang.TypeBool:
|
|
||||||
kind = ast.Bool
|
|
||||||
case clang.TypeCharU, clang.TypeUChar, clang.TypeCharS, clang.TypeSChar:
|
|
||||||
kind = ast.Char
|
|
||||||
case clang.TypeChar16:
|
|
||||||
kind = ast.Char16
|
|
||||||
case clang.TypeChar32:
|
|
||||||
kind = ast.Char32
|
|
||||||
case clang.TypeWChar:
|
|
||||||
kind = ast.WChar
|
|
||||||
case clang.TypeShort, clang.TypeUShort:
|
|
||||||
kind = ast.Int
|
|
||||||
flags |= ast.Short
|
|
||||||
case clang.TypeInt, clang.TypeUInt:
|
|
||||||
kind = ast.Int
|
|
||||||
case clang.TypeLong, clang.TypeULong:
|
|
||||||
kind = ast.Int
|
|
||||||
flags |= ast.Long
|
|
||||||
case clang.TypeLongLong, clang.TypeULongLong:
|
|
||||||
kind = ast.Int
|
|
||||||
flags |= ast.LongLong
|
|
||||||
case clang.TypeInt128, clang.TypeUInt128:
|
|
||||||
kind = ast.Int128
|
|
||||||
case clang.TypeFloat:
|
|
||||||
kind = ast.Float
|
|
||||||
case clang.TypeHalf, clang.TypeFloat16:
|
|
||||||
kind = ast.Float16
|
|
||||||
case clang.TypeDouble:
|
|
||||||
kind = ast.Float
|
|
||||||
flags |= ast.Double
|
|
||||||
case clang.TypeLongDouble:
|
|
||||||
kind = ast.Float
|
|
||||||
flags |= ast.Long | ast.Double
|
|
||||||
case clang.TypeFloat128:
|
|
||||||
kind = ast.Float128
|
|
||||||
case clang.TypeComplex:
|
|
||||||
kind = ast.Complex
|
|
||||||
complexKind := t.ElementType().Kind
|
|
||||||
if complexKind == clang.TypeLongDouble {
|
|
||||||
flags |= ast.Long | ast.Double
|
|
||||||
} else if complexKind == clang.TypeDouble {
|
|
||||||
flags |= ast.Double
|
|
||||||
}
|
|
||||||
// float complfex flag is not set
|
|
||||||
default:
|
|
||||||
// like IBM128,NullPtr,Accum
|
|
||||||
kindStr := toStr(t.Kind.String())
|
|
||||||
fmt.Fprintln(os.Stderr, "todo: unknown builtin type:", kindStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if IsExplicitSigned(t) {
|
|
||||||
flags |= ast.Signed
|
|
||||||
} else if IsExplicitUnsigned(t) {
|
|
||||||
flags |= ast.Unsigned
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ast.BuiltinType{
|
|
||||||
Kind: kind,
|
|
||||||
Flags: flags,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructs a complete scoping expression by traversing the semantic parents, starting from the given clang.Cursor
|
|
||||||
// For anonymous decl of typedef references, use their anonymous name
|
|
||||||
func (ct *Converter) BuildScopingExpr(cursor clang.Cursor) ast.Expr {
|
|
||||||
parts := clangutils.BuildScopingParts(cursor)
|
|
||||||
return buildScopingFromParts(parts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) MarshalASTFiles() *cjson.JSON {
|
|
||||||
return MarshalASTFiles(ct.Files)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ct *Converter) MarshalOutputASTFiles() *cjson.JSON {
|
|
||||||
return MarshalOutputASTFiles(ct.Files)
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsExplicitSigned(t clang.Type) bool {
|
|
||||||
return t.Kind == clang.TypeCharS || t.Kind == clang.TypeSChar
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsExplicitUnsigned(t clang.Type) bool {
|
|
||||||
return t.Kind == clang.TypeCharU || t.Kind == clang.TypeUChar ||
|
|
||||||
t.Kind == clang.TypeUShort || t.Kind == clang.TypeUInt ||
|
|
||||||
t.Kind == clang.TypeULong || t.Kind == clang.TypeULongLong ||
|
|
||||||
t.Kind == clang.TypeUInt128
|
|
||||||
}
|
|
||||||
|
|
||||||
func toTag(kind clang.CursorKind) ast.Tag {
|
|
||||||
switch kind {
|
|
||||||
case clang.CursorStructDecl:
|
|
||||||
return ast.Struct
|
|
||||||
case clang.CursorUnionDecl:
|
|
||||||
return ast.Union
|
|
||||||
case clang.CursorClassDecl:
|
|
||||||
return ast.Class
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("Unexpected cursor kind in toTag: %v", kind))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toToken(tok clang.Token) token.Token {
|
|
||||||
if tok.Kind() < clang.Punctuation || tok.Kind() > clang.Comment {
|
|
||||||
return token.ILLEGAL
|
|
||||||
} else {
|
|
||||||
return token.Token(tok.Kind() + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func isMethod(cursor clang.Cursor) bool {
|
|
||||||
return cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildScopingFromParts(parts []string) ast.Expr {
|
|
||||||
if len(parts) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var expr ast.Expr = &ast.Ident{Name: parts[0]}
|
|
||||||
for _, part := range parts[1:] {
|
|
||||||
expr = &ast.ScopingExpr{
|
|
||||||
Parent: expr,
|
|
||||||
X: &ast.Ident{Name: part},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return expr
|
|
||||||
}
|
|
||||||
|
|
||||||
// isCursorChildOf checks if the child cursor is contained within the parent cursor.
|
|
||||||
// This function is necessary because libclang doesn't correctly report the lexical
|
|
||||||
// or semantic parent for anonymous structs inside typedefs. By comparing source ranges,
|
|
||||||
// we can determine if one cursor is nested inside another.
|
|
||||||
func isCursorChildOf(child, parent clang.Cursor) bool {
|
|
||||||
return isRangeChildOf(child.Extent(), parent.Extent())
|
|
||||||
}
|
|
||||||
|
|
||||||
func isRangeChildOf(childRange, parentRange clang.SourceRange) bool {
|
|
||||||
return getOffset(childRange.RangeStart()) >= getOffset(parentRange.RangeStart()) &&
|
|
||||||
getOffset(childRange.RangeEnd()) <= getOffset(parentRange.RangeEnd())
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOffset(location clang.SourceLocation) c.Uint {
|
|
||||||
var offset c.Uint
|
|
||||||
location.SpellingLocation(nil, nil, nil, &offset)
|
|
||||||
return offset
|
|
||||||
}
|
|
||||||
|
|
||||||
func toStr(clangStr clang.String) (str string) {
|
|
||||||
defer clangStr.Dispose()
|
|
||||||
if clangStr.CStr() != nil {
|
|
||||||
str = c.GoString(clangStr.CStr())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTypeDesc(t clang.Type) (name string, kind string) {
|
|
||||||
name = toStr(t.String())
|
|
||||||
kind = toStr(t.Kind.String())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCursorDesc(cursor clang.Cursor) (name string, kind string) {
|
|
||||||
name = toStr(cursor.String())
|
|
||||||
kind = toStr(cursor.Kind.String())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package cvttest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RunTest(testName string, testCases []string) {
|
|
||||||
for i, content := range testCases {
|
|
||||||
c.Printf(c.Str("%s Case %d:\n"), c.AllocaCStr(testName), c.Int(i+1))
|
|
||||||
RunTestWithConfig(&clangutils.Config{
|
|
||||||
File: content,
|
|
||||||
Temp: true,
|
|
||||||
IsCpp: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunTestWithConfig(config *clangutils.Config) {
|
|
||||||
converter, err := parse.NewConverter(config)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = converter.Convert()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := converter.MarshalASTFiles()
|
|
||||||
str := result.Print()
|
|
||||||
c.Printf(c.Str("%s\n\n"), str)
|
|
||||||
|
|
||||||
cjson.FreeCStr(str)
|
|
||||||
result.Delete()
|
|
||||||
converter.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetTypeOptions struct {
|
|
||||||
TypeCode string // e.g. "char*", "char**"
|
|
||||||
|
|
||||||
// ExpectTypeKind specifies the expected type kind (optional)
|
|
||||||
// Use clang.Type_Invalid to accept any type (default behavior)
|
|
||||||
// *For complex types (when <complex.h> is included), specifying this is crucial
|
|
||||||
// to filter out the correct type, as there will be multiple VarDecl fields present
|
|
||||||
ExpectTypeKind clang.TypeKind
|
|
||||||
|
|
||||||
// Args contains additional compilation arguments passed to Clang (optional)
|
|
||||||
// These are appended after the default language-specific arguments
|
|
||||||
// Example: []string{"-std=c++11"}
|
|
||||||
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
|
|
||||||
// Need to dispose the index and unit after using
|
|
||||||
// e.g. index.Dispose(), unit.Dispose()
|
|
||||||
func GetType(option *GetTypeOptions) (clang.Type, *clang.Index, *clang.TranslationUnit) {
|
|
||||||
code := fmt.Sprintf("%s placeholder;", option.TypeCode)
|
|
||||||
index, unit, err := clangutils.CreateTranslationUnit(&clangutils.Config{
|
|
||||||
File: code,
|
|
||||||
Temp: true,
|
|
||||||
Args: option.Args,
|
|
||||||
IsCpp: option.IsCpp,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
cursor := unit.Cursor()
|
|
||||||
var typ clang.Type
|
|
||||||
parse.VisitChildren(cursor, func(child, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
if child.Kind == clang.CursorVarDecl && (option.ExpectTypeKind == clang.TypeInvalid || option.ExpectTypeKind == child.Type().Kind) {
|
|
||||||
typ = child.Type()
|
|
||||||
return clang.ChildVisit_Break
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
})
|
|
||||||
return typ, index, unit
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestClassDecl()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClassDecl() {
|
|
||||||
testCases := []string{
|
|
||||||
`class A {
|
|
||||||
public:
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
};`,
|
|
||||||
`class A {
|
|
||||||
public:
|
|
||||||
static int a;
|
|
||||||
int b;
|
|
||||||
float foo(int a,double b);
|
|
||||||
private:
|
|
||||||
static void bar();
|
|
||||||
protected:
|
|
||||||
void bar2();
|
|
||||||
};`,
|
|
||||||
`class A {
|
|
||||||
public:
|
|
||||||
A();
|
|
||||||
explicit A();
|
|
||||||
~A();
|
|
||||||
static inline void foo();
|
|
||||||
};`,
|
|
||||||
`class Base {
|
|
||||||
public:
|
|
||||||
Base();
|
|
||||||
virtual ~Base();
|
|
||||||
virtual void foo();
|
|
||||||
};
|
|
||||||
class Derived : public Base {
|
|
||||||
public:
|
|
||||||
Derived();
|
|
||||||
~Derived() override;
|
|
||||||
void foo() override;
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
`namespace A{
|
|
||||||
class Foo{}
|
|
||||||
}
|
|
||||||
void A::Foo::bar();
|
|
||||||
`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestClassDecl", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,713 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestClassDecl Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestClassDecl Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": true,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1A3fooEid",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 8,
|
|
||||||
"Flags": 16
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 8,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestClassDecl Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1AC1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": true,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1AC1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": true,
|
|
||||||
"IsConstructor": true,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "~A"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1AD1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": true,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1A3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": true,
|
|
||||||
"IsStatic": true,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestClassDecl Case 4:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Base"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Base"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Base"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN4BaseC1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": true,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Base"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "~Base"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN4BaseD1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": true,
|
|
||||||
"IsVirtual": true,
|
|
||||||
"IsOverride": false
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Base"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN4Base3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": true,
|
|
||||||
"IsOverride": false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Derived"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Derived"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Derived"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN7DerivedC1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": true,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Derived"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "~Derived"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN7DerivedD1Ev",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": true,
|
|
||||||
"IsVirtual": true,
|
|
||||||
"IsOverride": true
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Derived"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN7Derived3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": true,
|
|
||||||
"IsOverride": true
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestClassDecl Case 5:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "bar"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1A3Foo3barEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestDoc()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDoc() {
|
|
||||||
testCases := []string{
|
|
||||||
`
|
|
||||||
// not read doc 1
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/* not read doc 2 */
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/// doc
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/** doc */
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/*! doc */
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/// doc 1
|
|
||||||
/// doc 2
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/*! doc 1 */
|
|
||||||
/*! doc 2 */
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/** doc 1 */
|
|
||||||
/** doc 1 */
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
/**
|
|
||||||
* doc 1
|
|
||||||
* doc 2
|
|
||||||
*/
|
|
||||||
void foo();`,
|
|
||||||
`
|
|
||||||
struct Foo {
|
|
||||||
/// doc
|
|
||||||
int x;
|
|
||||||
int y; ///< comment
|
|
||||||
/**
|
|
||||||
* field doc (parse ignore with comment in same cursor)
|
|
||||||
*/
|
|
||||||
int z; /*!< comment */
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
`
|
|
||||||
class Doc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* static field doc
|
|
||||||
*/
|
|
||||||
static int x;
|
|
||||||
static int y; /*!< static field comment */
|
|
||||||
/**
|
|
||||||
* field doc
|
|
||||||
*/
|
|
||||||
int a;
|
|
||||||
int b; ///< field comment
|
|
||||||
/**
|
|
||||||
* method doc
|
|
||||||
*/
|
|
||||||
void Foo();
|
|
||||||
protected:
|
|
||||||
int value; /*!< protected field comment */
|
|
||||||
};`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestDoc", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,742 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestDoc Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/// doc\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 4:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/** doc */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 5:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/*! doc */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 6:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/// doc 1\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/// doc 2\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 7:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/*! doc 1 */\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/*! doc 2 */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 8:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/** doc 1 */\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/** doc 1 */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 9:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/**\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " * doc 1\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " * doc 2\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 10:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/// doc\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "x"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "///< comment\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "y"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/*!< comment */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "z"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDoc Case 11:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Doc"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/** \n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " * static field doc\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": true,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "x"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/*!< static field comment */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"IsStatic": true,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "y"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/** \n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " * field doc\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "///< field comment\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/*!< protected field comment */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 2,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "value"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": {
|
|
||||||
"_Type": "CommentGroup",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": "/** \n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " * method doc\n"
|
|
||||||
}, {
|
|
||||||
"_Type": "Comment",
|
|
||||||
"Text": " */\n"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Doc"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN3Doc3FooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestEnumDecl()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnumDecl() {
|
|
||||||
testCases := []string{
|
|
||||||
`enum {
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
};`,
|
|
||||||
`enum Foo {
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
};`,
|
|
||||||
`enum Foo {
|
|
||||||
a = 1,
|
|
||||||
b = 2,
|
|
||||||
c = 4,
|
|
||||||
};`,
|
|
||||||
`enum Foo {
|
|
||||||
a = 1,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
};`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestEnumDecl", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,238 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestEnumDecl Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "EnumTypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": null,
|
|
||||||
"Type": {
|
|
||||||
"_Type": "EnumType",
|
|
||||||
"Items": [{
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "0"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "1"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestEnumDecl Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "EnumTypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "EnumType",
|
|
||||||
"Items": [{
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "0"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "1"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "2"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestEnumDecl Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "EnumTypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "EnumType",
|
|
||||||
"Items": [{
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "1"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "2"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "4"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestEnumDecl Case 4:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "EnumTypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "EnumType",
|
|
||||||
"Items": [{
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "1"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "2"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "3"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestFuncDecl()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFuncDecl() {
|
|
||||||
testCases := []string{
|
|
||||||
`void foo();`,
|
|
||||||
`void foo(int a);`,
|
|
||||||
`void foo(int a,...);`,
|
|
||||||
`float* foo(int a,double b);`,
|
|
||||||
`static inline int add(int a, int b);`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestFuncDecl", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,323 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestFuncDecl Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestFuncDecl Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3fooi",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestFuncDecl Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3fooiz",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "Variadic"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": null
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestFuncDecl Case 4:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3fooid",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 8,
|
|
||||||
"Flags": 16
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 8,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestFuncDecl Case 5:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "add"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZL3addii",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": true,
|
|
||||||
"IsStatic": true,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestScope Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_Z3foov",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestScope Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1a3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestScope Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1a1b3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestScope Case 4:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1a3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestScope Case 5:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Methods": [{
|
|
||||||
"_Type": "FuncDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "foo"
|
|
||||||
},
|
|
||||||
"MangledName": "_ZN1a1b3fooEv",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": null
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 0,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IsInline": false,
|
|
||||||
"IsStatic": false,
|
|
||||||
"IsConst": false,
|
|
||||||
"IsExplicit": false,
|
|
||||||
"IsConstructor": false,
|
|
||||||
"IsDestructor": false,
|
|
||||||
"IsVirtual": false,
|
|
||||||
"IsOverride": false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestScope()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScope() {
|
|
||||||
testCases := []string{
|
|
||||||
`void foo();`,
|
|
||||||
`namespace a {
|
|
||||||
void foo();
|
|
||||||
}`,
|
|
||||||
`namespace a {
|
|
||||||
namespace b {
|
|
||||||
void foo();
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
`class a {
|
|
||||||
public:
|
|
||||||
void foo();
|
|
||||||
};`,
|
|
||||||
`namespace a {
|
|
||||||
class b {
|
|
||||||
public:
|
|
||||||
void foo();
|
|
||||||
};
|
|
||||||
}`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestScope", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,375 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestStructDecl Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": null,
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestStructDecl Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestStructDecl Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestStructDecl Case 4:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": null
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": null
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestStructDecl Case 5:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Person"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "age"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "year"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "day"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "month"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "birthday"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestStructDecl()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStructDecl() {
|
|
||||||
testCases := []string{
|
|
||||||
`struct {
|
|
||||||
int a;
|
|
||||||
};`,
|
|
||||||
`struct A {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
};`,
|
|
||||||
`struct A {
|
|
||||||
int a, b;
|
|
||||||
};`,
|
|
||||||
`struct A {
|
|
||||||
int a;
|
|
||||||
int (*Foo)(int, int);
|
|
||||||
};`,
|
|
||||||
`struct Person {
|
|
||||||
int age;
|
|
||||||
struct {
|
|
||||||
int year;
|
|
||||||
int day;
|
|
||||||
int month;
|
|
||||||
} birthday;
|
|
||||||
};`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestStructDecl", testCases)
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestTypeDefDecl()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTypeDefDecl() {
|
|
||||||
testCases := []string{
|
|
||||||
`typedef int INT;`,
|
|
||||||
|
|
||||||
`typedef int INT;
|
|
||||||
typedef INT STANDARD_INT;`,
|
|
||||||
|
|
||||||
`typedef int INT,*IntPtr,IntArr[];`,
|
|
||||||
|
|
||||||
`typedef int (*Foo)(int, int, ...);`,
|
|
||||||
|
|
||||||
`typedef int (*Foo)(int, int),(*Bar)(void*,void*);`,
|
|
||||||
|
|
||||||
`namespace A {
|
|
||||||
typedef class Foo{
|
|
||||||
int x;
|
|
||||||
} MyClass,*MyClassPtr,MyClassArray[];
|
|
||||||
}`,
|
|
||||||
|
|
||||||
`typedef struct {
|
|
||||||
int x;
|
|
||||||
} MyStruct`,
|
|
||||||
`typedef union {
|
|
||||||
int x;
|
|
||||||
} MyUnion`,
|
|
||||||
`typedef enum {
|
|
||||||
RED,
|
|
||||||
GREEN,
|
|
||||||
BLUE
|
|
||||||
} MyEnum`,
|
|
||||||
|
|
||||||
`typedef struct {
|
|
||||||
int x;
|
|
||||||
} MyStruct,MyStruct2,*StructPtr, StructArr[];`,
|
|
||||||
|
|
||||||
`typedef enum {
|
|
||||||
RED,
|
|
||||||
GREEN,
|
|
||||||
BLUE
|
|
||||||
} MyEnum,MyEnum2,*EnumPtr,EnumArr[];`,
|
|
||||||
|
|
||||||
`namespace A{
|
|
||||||
namespace B{
|
|
||||||
typedef struct {
|
|
||||||
int x;
|
|
||||||
} MyStruct,MyStruct2,*StructPtr, StructArr[];
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestTypeDefDecl", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestUnionDecl Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": null,
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 1,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestUnionDecl Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "A"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 1,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestUnionDecl Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "temp.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "OuterUnion"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 1,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "i"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 8,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "f"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 1,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 32
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "s"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "inner"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestUnionDecl()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnionDecl() {
|
|
||||||
testCases := []string{
|
|
||||||
`union {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
};`,
|
|
||||||
`union A {
|
|
||||||
int a;
|
|
||||||
int b;
|
|
||||||
};`,
|
|
||||||
`union OuterUnion {
|
|
||||||
int i;
|
|
||||||
float f;
|
|
||||||
union {
|
|
||||||
int c;
|
|
||||||
short s;
|
|
||||||
} inner;
|
|
||||||
};`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestUnionDecl", testCases)
|
|
||||||
}
|
|
||||||
@@ -1,231 +0,0 @@
|
|||||||
#stdout
|
|
||||||
TestDefine Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [],
|
|
||||||
"includes": [],
|
|
||||||
"macros": [{
|
|
||||||
"_Type": "Macro",
|
|
||||||
"Name": "DEBUG",
|
|
||||||
"Tokens": [{
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "DEBUG"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDefine Case 2:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [],
|
|
||||||
"includes": [],
|
|
||||||
"macros": [{
|
|
||||||
"_Type": "Macro",
|
|
||||||
"Name": "OK",
|
|
||||||
"Tokens": [{
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "OK"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 4,
|
|
||||||
"Lit": "1"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestDefine Case 3:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [],
|
|
||||||
"includes": [],
|
|
||||||
"macros": [{
|
|
||||||
"_Type": "Macro",
|
|
||||||
"Name": "SQUARE",
|
|
||||||
"Tokens": [{
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "SQUARE"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "("
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "x"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": ")"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "("
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "("
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "x"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": ")"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "*"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "("
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "x"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": ")"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": ")"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestInclude Case 1:
|
|
||||||
{
|
|
||||||
"temp.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [],
|
|
||||||
"includes": [{
|
|
||||||
"_Type": "Include",
|
|
||||||
"Path": "foo.h"
|
|
||||||
}],
|
|
||||||
"macros": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TestMacroExpansionOtherFile:
|
|
||||||
{
|
|
||||||
"./testdata/macroexpan/ref.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [{
|
|
||||||
"_Type": "TypeDecl",
|
|
||||||
"Loc": {
|
|
||||||
"_Type": "Location",
|
|
||||||
"File": "./testdata/macroexpan/ref.h"
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Parent": null,
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "NewType"
|
|
||||||
},
|
|
||||||
"Type": {
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "ArrayType",
|
|
||||||
"Elt": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Len": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "__val"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
"includes": [{
|
|
||||||
"_Type": "Include",
|
|
||||||
"Path": "def.h"
|
|
||||||
}],
|
|
||||||
"macros": []
|
|
||||||
},
|
|
||||||
"./testdata/macroexpan/def.h": {
|
|
||||||
"_Type": "File",
|
|
||||||
"decls": [],
|
|
||||||
"includes": [],
|
|
||||||
"macros": [{
|
|
||||||
"_Type": "Macro",
|
|
||||||
"Name": "__FSID_T_TYPE",
|
|
||||||
"Tokens": [{
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "__FSID_T_TYPE"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 2,
|
|
||||||
"Lit": "struct"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "{"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 2,
|
|
||||||
"Lit": "int"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 3,
|
|
||||||
"Lit": "__val"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "["
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 4,
|
|
||||||
"Lit": "2"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "]"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": ";"
|
|
||||||
}, {
|
|
||||||
"_Type": "Token",
|
|
||||||
"Token": 1,
|
|
||||||
"Lit": "}"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestDefine()
|
|
||||||
TestInclude()
|
|
||||||
TestMacroExpansionOtherFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDefine() {
|
|
||||||
testCases := []string{
|
|
||||||
`#define DEBUG`,
|
|
||||||
`#define OK 1`,
|
|
||||||
`#define SQUARE(x) ((x) * (x))`,
|
|
||||||
}
|
|
||||||
test.RunTest("TestDefine", testCases)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInclude() {
|
|
||||||
testCases := []string{
|
|
||||||
`#include "foo.h"`,
|
|
||||||
// `#include <limits.h>`, // Standard libraries are mostly platform-dependent
|
|
||||||
}
|
|
||||||
test.RunTest("TestInclude", testCases)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMacroExpansionOtherFile() {
|
|
||||||
c.Printf(c.Str("TestMacroExpansionOtherFile:\n"))
|
|
||||||
test.RunTestWithConfig(&clangutils.Config{
|
|
||||||
File: "./testdata/macroexpan/ref.h",
|
|
||||||
Temp: false,
|
|
||||||
IsCpp: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#define __FSID_T_TYPE \
|
|
||||||
struct { \
|
|
||||||
int __val[2]; \
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
#include "def.h"
|
|
||||||
typedef __FSID_T_TYPE NewType;
|
|
||||||
@@ -1,351 +0,0 @@
|
|||||||
#stdout
|
|
||||||
Char's flags is signed or unsigned
|
|
||||||
Void:flags:0 kind:0
|
|
||||||
Bool:flags:0 kind:1
|
|
||||||
Char_S:flags:1 kind:2
|
|
||||||
Char_U:flags:2 kind:2
|
|
||||||
Char16:flags:0 kind:3
|
|
||||||
Char32:flags:0 kind:4
|
|
||||||
WChar:flags:0 kind:5
|
|
||||||
Short:flags:32 kind:6
|
|
||||||
UShort:flags:34 kind:6
|
|
||||||
Int:flags:0 kind:6
|
|
||||||
UInt:flags:2 kind:6
|
|
||||||
Long:flags:4 kind:6
|
|
||||||
ULong:flags:6 kind:6
|
|
||||||
LongLong:flags:8 kind:6
|
|
||||||
ULongLong:flags:10 kind:6
|
|
||||||
Int128:flags:0 kind:7
|
|
||||||
UInt128:flags:2 kind:7
|
|
||||||
Float:flags:0 kind:8
|
|
||||||
Half:flags:0 kind:9
|
|
||||||
Float16:flags:0 kind:9
|
|
||||||
Double:flags:16 kind:8
|
|
||||||
LongDouble:flags:20 kind:8
|
|
||||||
Float128:flags:0 kind:10
|
|
||||||
Complex:flags:0 kind:11
|
|
||||||
Complex:flags:16 kind:11
|
|
||||||
Complex:flags:20 kind:11
|
|
||||||
Unknown:flags:0 kind:0
|
|
||||||
Type: int *:
|
|
||||||
{
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: int ***:
|
|
||||||
{
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: int[]:
|
|
||||||
{
|
|
||||||
"_Type": "ArrayType",
|
|
||||||
"Elt": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Len": null
|
|
||||||
}
|
|
||||||
Type: int[10]:
|
|
||||||
{
|
|
||||||
"_Type": "ArrayType",
|
|
||||||
"Elt": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Len": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "10"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: int[3][4]:
|
|
||||||
{
|
|
||||||
"_Type": "ArrayType",
|
|
||||||
"Elt": {
|
|
||||||
"_Type": "ArrayType",
|
|
||||||
"Elt": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Len": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Len": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: int &:
|
|
||||||
{
|
|
||||||
"_Type": "LvalueRefType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: int &&:
|
|
||||||
{
|
|
||||||
"_Type": "RvalueRefType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: Foo:
|
|
||||||
{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
}
|
|
||||||
Type: struct Foo:
|
|
||||||
{
|
|
||||||
"_Type": "TagExpr",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Tag": 0
|
|
||||||
}
|
|
||||||
Type: struct (unnamed struct at temp.h:1:1):
|
|
||||||
{
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 0,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "x"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
Type: Foo:
|
|
||||||
{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
}
|
|
||||||
Type: union Foo:
|
|
||||||
{
|
|
||||||
"_Type": "TagExpr",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Tag": 1
|
|
||||||
}
|
|
||||||
Type: union (unnamed union at temp.h:1:1):
|
|
||||||
{
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 1,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 1,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "x"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
Type: Foo:
|
|
||||||
{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
}
|
|
||||||
Type: enum Foo:
|
|
||||||
{
|
|
||||||
"_Type": "TagExpr",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Tag": 2
|
|
||||||
}
|
|
||||||
Type: enum (unnamed enum at temp.h:1:1):
|
|
||||||
{
|
|
||||||
"_Type": "EnumType",
|
|
||||||
"Items": [{
|
|
||||||
"_Type": "EnumItem",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "x"
|
|
||||||
},
|
|
||||||
"Value": {
|
|
||||||
"_Type": "BasicLit",
|
|
||||||
"Kind": 0,
|
|
||||||
"Value": "42"
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
Type: Foo:
|
|
||||||
{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
}
|
|
||||||
Type: class Foo:
|
|
||||||
{
|
|
||||||
"_Type": "TagExpr",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "Foo"
|
|
||||||
},
|
|
||||||
"Tag": 3
|
|
||||||
}
|
|
||||||
Type: class (unnamed class at temp.h:1:1):
|
|
||||||
{
|
|
||||||
"_Type": "RecordType",
|
|
||||||
"Tag": 3,
|
|
||||||
"Fields": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 3,
|
|
||||||
"Names": [{
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "x"
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Methods": []
|
|
||||||
}
|
|
||||||
Type: a::b::c:
|
|
||||||
{
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type: class a::b::c:
|
|
||||||
{
|
|
||||||
"_Type": "TagExpr",
|
|
||||||
"Name": {
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "c"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "ScopingExpr",
|
|
||||||
"X": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "b"
|
|
||||||
},
|
|
||||||
"Parent": {
|
|
||||||
"_Type": "Ident",
|
|
||||||
"Name": "a"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Tag": 3
|
|
||||||
}
|
|
||||||
Type: int (*)(int, int):
|
|
||||||
{
|
|
||||||
"_Type": "PointerType",
|
|
||||||
"X": {
|
|
||||||
"_Type": "FuncType",
|
|
||||||
"Params": {
|
|
||||||
"_Type": "FieldList",
|
|
||||||
"List": [{
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": null
|
|
||||||
}, {
|
|
||||||
"_Type": "Field",
|
|
||||||
"Type": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
},
|
|
||||||
"Doc": null,
|
|
||||||
"Comment": null,
|
|
||||||
"IsStatic": false,
|
|
||||||
"Access": 0,
|
|
||||||
"Names": null
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
"Ret": {
|
|
||||||
"_Type": "BuiltinType",
|
|
||||||
"Kind": 6,
|
|
||||||
"Flags": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
todo: unknown builtin type: Ibm128
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse"
|
|
||||||
test "github.com/goplus/llgo/chore/_xtool/llcppsigfetch/parse/cvt_test"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestChar()
|
|
||||||
TestBuiltinType()
|
|
||||||
TestNonBuiltinTypes()
|
|
||||||
}
|
|
||||||
func TestBuiltinType() {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
typ clang.Type
|
|
||||||
expected ast.BuiltinType
|
|
||||||
}{
|
|
||||||
{"Void", btType(clang.TypeVoid), ast.BuiltinType{Kind: ast.Void}},
|
|
||||||
{"Bool", btType(clang.TypeBool), ast.BuiltinType{Kind: ast.Bool}},
|
|
||||||
{"Char_S", btType(clang.TypeCharS), ast.BuiltinType{Kind: ast.Char, Flags: ast.Signed}},
|
|
||||||
{"Char_U", btType(clang.TypeCharU), ast.BuiltinType{Kind: ast.Char, Flags: ast.Unsigned}},
|
|
||||||
{"Char16", btType(clang.TypeChar16), ast.BuiltinType{Kind: ast.Char16}},
|
|
||||||
{"Char32", btType(clang.TypeChar32), ast.BuiltinType{Kind: ast.Char32}},
|
|
||||||
{"WChar", btType(clang.TypeWChar), ast.BuiltinType{Kind: ast.WChar}},
|
|
||||||
{"Short", btType(clang.TypeShort), ast.BuiltinType{Kind: ast.Int, Flags: ast.Short}},
|
|
||||||
{"UShort", btType(clang.TypeUShort), ast.BuiltinType{Kind: ast.Int, Flags: ast.Short | ast.Unsigned}},
|
|
||||||
{"Int", btType(clang.TypeInt), ast.BuiltinType{Kind: ast.Int}},
|
|
||||||
{"UInt", btType(clang.TypeUInt), ast.BuiltinType{Kind: ast.Int, Flags: ast.Unsigned}},
|
|
||||||
{"Long", btType(clang.TypeLong), ast.BuiltinType{Kind: ast.Int, Flags: ast.Long}},
|
|
||||||
{"ULong", btType(clang.TypeULong), ast.BuiltinType{Kind: ast.Int, Flags: ast.Long | ast.Unsigned}},
|
|
||||||
{"LongLong", btType(clang.TypeLongLong), ast.BuiltinType{Kind: ast.Int, Flags: ast.LongLong}},
|
|
||||||
{"ULongLong", btType(clang.TypeULongLong), ast.BuiltinType{Kind: ast.Int, Flags: ast.LongLong | ast.Unsigned}},
|
|
||||||
{"Int128", btType(clang.TypeInt128), ast.BuiltinType{Kind: ast.Int128}},
|
|
||||||
{"UInt128", btType(clang.TypeUInt128), ast.BuiltinType{Kind: ast.Int128, Flags: ast.Unsigned}},
|
|
||||||
{"Float", btType(clang.TypeFloat), ast.BuiltinType{Kind: ast.Float}},
|
|
||||||
{"Half", btType(clang.TypeHalf), ast.BuiltinType{Kind: ast.Float16}},
|
|
||||||
{"Float16", btType(clang.TypeFloat16), ast.BuiltinType{Kind: ast.Float16}},
|
|
||||||
{"Double", btType(clang.TypeDouble), ast.BuiltinType{Kind: ast.Float, Flags: ast.Double}},
|
|
||||||
{"LongDouble", btType(clang.TypeLongDouble), ast.BuiltinType{Kind: ast.Float, Flags: ast.Long | ast.Double}},
|
|
||||||
{"Float128", btType(clang.TypeFloat128), ast.BuiltinType{Kind: ast.Float128}},
|
|
||||||
{"Complex", getComplexType(0), ast.BuiltinType{Kind: ast.Complex}},
|
|
||||||
{"Complex", getComplexType(ast.Double), ast.BuiltinType{Flags: ast.Double, Kind: ast.Complex}},
|
|
||||||
{"Complex", getComplexType(ast.Long | ast.Double), ast.BuiltinType{Flags: ast.Long | ast.Double, Kind: ast.Complex}},
|
|
||||||
{"Unknown", btType(clang.TypeIbm128), ast.BuiltinType{Kind: ast.Void}},
|
|
||||||
}
|
|
||||||
|
|
||||||
converter := &parse.Converter{}
|
|
||||||
converter.Convert()
|
|
||||||
for _, bt := range tests {
|
|
||||||
res := converter.ProcessBuiltinType(bt.typ)
|
|
||||||
if res.Kind != bt.expected.Kind {
|
|
||||||
fmt.Printf("%s Kind mismatch:got %d want %d, \n", bt.name, res.Kind, bt.expected.Kind)
|
|
||||||
}
|
|
||||||
if res.Flags != bt.expected.Flags {
|
|
||||||
fmt.Printf("%s Flags mismatch:got %d,want %d\n", bt.name, res.Flags, bt.expected.Flags)
|
|
||||||
}
|
|
||||||
fmt.Printf("%s:flags:%d kind:%d\n", bt.name, res.Flags, res.Kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Char's Default Type in macos is signed char & in linux is unsigned char
|
|
||||||
// So we only confirm the char's kind is char & flags is unsigned or signed
|
|
||||||
func TestChar() {
|
|
||||||
typ, index, transunit := test.GetType(&test.GetTypeOptions{
|
|
||||||
TypeCode: "char",
|
|
||||||
IsCpp: false,
|
|
||||||
})
|
|
||||||
converter := &parse.Converter{}
|
|
||||||
expr := converter.ProcessType(typ)
|
|
||||||
if btType, ok := expr.(*ast.BuiltinType); ok {
|
|
||||||
if btType.Kind == ast.Char {
|
|
||||||
if btType.Flags == ast.Signed || btType.Flags == ast.Unsigned {
|
|
||||||
fmt.Println("Char's flags is signed or unsigned")
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(os.Stderr, "Char's flags is not signed or unsigned")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(os.Stderr, "Char's expr is not a builtin type")
|
|
||||||
}
|
|
||||||
index.Dispose()
|
|
||||||
transunit.Dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNonBuiltinTypes() {
|
|
||||||
tests := []string{
|
|
||||||
"int*",
|
|
||||||
"int***",
|
|
||||||
|
|
||||||
"int[]",
|
|
||||||
"int[10]",
|
|
||||||
"int[3][4]",
|
|
||||||
|
|
||||||
"int&",
|
|
||||||
"int&&",
|
|
||||||
|
|
||||||
`struct Foo {};
|
|
||||||
Foo`,
|
|
||||||
`struct Foo {};
|
|
||||||
struct Foo`,
|
|
||||||
`struct {
|
|
||||||
int x;
|
|
||||||
}`,
|
|
||||||
|
|
||||||
`union Foo {};
|
|
||||||
Foo`,
|
|
||||||
`union Foo {};
|
|
||||||
union Foo`,
|
|
||||||
`union {
|
|
||||||
int x;
|
|
||||||
}`,
|
|
||||||
|
|
||||||
`enum Foo {};
|
|
||||||
Foo`,
|
|
||||||
`enum Foo {};
|
|
||||||
enum Foo`,
|
|
||||||
`enum { x = 42 }`,
|
|
||||||
|
|
||||||
`class Foo {};
|
|
||||||
Foo`,
|
|
||||||
`class Foo {};
|
|
||||||
class Foo`,
|
|
||||||
`class {
|
|
||||||
int x;
|
|
||||||
}`,
|
|
||||||
|
|
||||||
`namespace a {
|
|
||||||
namespace b {
|
|
||||||
class c {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a::b::c`,
|
|
||||||
|
|
||||||
`namespace a {
|
|
||||||
namespace b {
|
|
||||||
class c {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class a::b::c`,
|
|
||||||
|
|
||||||
`int (*p)(int, int);`,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, t := range tests {
|
|
||||||
typ, index, unit := test.GetType(&test.GetTypeOptions{
|
|
||||||
TypeCode: t,
|
|
||||||
IsCpp: true,
|
|
||||||
})
|
|
||||||
converter := &parse.Converter{}
|
|
||||||
expr := converter.ProcessType(typ)
|
|
||||||
json := parse.MarshalASTExpr(expr)
|
|
||||||
str := json.Print()
|
|
||||||
typstr := typ.String()
|
|
||||||
|
|
||||||
c.Printf(c.Str("Type: %s:\n"), typstr)
|
|
||||||
c.Printf(c.Str("%s\n"), str)
|
|
||||||
|
|
||||||
typstr.Dispose()
|
|
||||||
cjson.FreeCStr(str)
|
|
||||||
json.Delete()
|
|
||||||
index.Dispose()
|
|
||||||
unit.Dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func btType(kind clang.TypeKind) clang.Type {
|
|
||||||
return clang.Type{Kind: kind}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get complex type from source code parsed
|
|
||||||
func getComplexType(flag ast.TypeFlag) clang.Type {
|
|
||||||
var typeStr string
|
|
||||||
if flag&(ast.Long|ast.Double) == (ast.Long | ast.Double) {
|
|
||||||
typeStr = "long double"
|
|
||||||
} else if flag&ast.Double != 0 {
|
|
||||||
typeStr = "double"
|
|
||||||
} else {
|
|
||||||
typeStr = "float"
|
|
||||||
}
|
|
||||||
|
|
||||||
code := fmt.Sprintf("#include <complex.h>\n%s complex", typeStr)
|
|
||||||
|
|
||||||
// todo(zzy):free index and unit after test
|
|
||||||
typ, _, _ := test.GetType(&test.GetTypeOptions{
|
|
||||||
TypeCode: code,
|
|
||||||
ExpectTypeKind: clang.TypeComplex,
|
|
||||||
IsCpp: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
@@ -1,273 +0,0 @@
|
|||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalOutputASTFiles(files []*FileEntry) *cjson.JSON {
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, entry := range files {
|
|
||||||
f := cjson.Object()
|
|
||||||
path := cjson.String(c.AllocaCStr(entry.Path))
|
|
||||||
f.SetItem(c.Str("path"), path)
|
|
||||||
f.SetItem(c.Str("doc"), MarshalASTFile(entry.Doc))
|
|
||||||
root.AddItem(f)
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalASTFiles(files []*FileEntry) *cjson.JSON {
|
|
||||||
root := cjson.Object()
|
|
||||||
for _, entry := range files {
|
|
||||||
root.SetItem(c.AllocaCStr(entry.Path), MarshalASTFile(entry.Doc))
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalDeclList(list []ast.Decl) *cjson.JSON {
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, item := range list {
|
|
||||||
root.AddItem(MarshalASTDecl(item))
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalFieldList(list []*ast.Field) *cjson.JSON {
|
|
||||||
if list == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, item := range list {
|
|
||||||
root.AddItem(MarshalASTExpr(item))
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalIncludeList(list []*ast.Include) *cjson.JSON {
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, item := range list {
|
|
||||||
include := cjson.Object()
|
|
||||||
include.SetItem(c.Str("_Type"), stringField("Include"))
|
|
||||||
include.SetItem(c.Str("Path"), stringField(item.Path))
|
|
||||||
root.AddItem(include)
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalMacroList(list []*ast.Macro) *cjson.JSON {
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, item := range list {
|
|
||||||
macro := cjson.Object()
|
|
||||||
macro.SetItem(c.Str("_Type"), stringField("Macro"))
|
|
||||||
macro.SetItem(c.Str("Name"), stringField(item.Name))
|
|
||||||
macro.SetItem(c.Str("Tokens"), MarshalTokenList(item.Tokens))
|
|
||||||
root.AddItem(macro)
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalTokenList(list []*ast.Token) *cjson.JSON {
|
|
||||||
if list == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, item := range list {
|
|
||||||
root.AddItem(MarshalToken(item))
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalIdentList(list []*ast.Ident) *cjson.JSON {
|
|
||||||
if list == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
root := cjson.Array()
|
|
||||||
for _, item := range list {
|
|
||||||
root.AddItem(MarshalASTExpr(item))
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalASTFile(file *ast.File) *cjson.JSON {
|
|
||||||
root := cjson.Object()
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("File"))
|
|
||||||
root.SetItem(c.Str("decls"), MarshalDeclList(file.Decls))
|
|
||||||
root.SetItem(c.Str("includes"), MarshalIncludeList(file.Includes))
|
|
||||||
root.SetItem(c.Str("macros"), MarshalMacroList(file.Macros))
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalToken(tok *ast.Token) *cjson.JSON {
|
|
||||||
root := cjson.Object()
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("Token"))
|
|
||||||
root.SetItem(c.Str("Token"), numberField(uint(tok.Token)))
|
|
||||||
root.SetItem(c.Str("Lit"), stringField(tok.Lit))
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalASTDecl(decl ast.Decl) *cjson.JSON {
|
|
||||||
if decl == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
root := cjson.Object()
|
|
||||||
switch d := decl.(type) {
|
|
||||||
case *ast.EnumTypeDecl:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("EnumTypeDecl"))
|
|
||||||
MarshalASTDeclBase(d.DeclBase, root)
|
|
||||||
root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name))
|
|
||||||
root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type))
|
|
||||||
case *ast.TypedefDecl:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("TypedefDecl"))
|
|
||||||
MarshalASTDeclBase(d.DeclBase, root)
|
|
||||||
root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name))
|
|
||||||
root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type))
|
|
||||||
case *ast.FuncDecl:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("FuncDecl"))
|
|
||||||
MarshalASTDeclBase(d.DeclBase, root)
|
|
||||||
root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name))
|
|
||||||
root.SetItem(c.Str("MangledName"), stringField(d.MangledName))
|
|
||||||
root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type))
|
|
||||||
root.SetItem(c.Str("IsInline"), boolField(d.IsInline))
|
|
||||||
root.SetItem(c.Str("IsStatic"), boolField(d.IsStatic))
|
|
||||||
root.SetItem(c.Str("IsConst"), boolField(d.IsConst))
|
|
||||||
root.SetItem(c.Str("IsExplicit"), boolField(d.IsExplicit))
|
|
||||||
root.SetItem(c.Str("IsConstructor"), boolField(d.IsConstructor))
|
|
||||||
root.SetItem(c.Str("IsDestructor"), boolField(d.IsDestructor))
|
|
||||||
root.SetItem(c.Str("IsVirtual"), boolField(d.IsVirtual))
|
|
||||||
root.SetItem(c.Str("IsOverride"), boolField(d.IsOverride))
|
|
||||||
case *ast.TypeDecl:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("TypeDecl"))
|
|
||||||
MarshalASTDeclBase(d.DeclBase, root)
|
|
||||||
root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name))
|
|
||||||
root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type))
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalASTDeclBase(decl ast.DeclBase, root *cjson.JSON) {
|
|
||||||
loc := cjson.Object()
|
|
||||||
loc.SetItem(c.Str("_Type"), stringField("Location"))
|
|
||||||
loc.SetItem(c.Str("File"), stringField(decl.Loc.File))
|
|
||||||
root.SetItem(c.Str("Loc"), loc)
|
|
||||||
root.SetItem(c.Str("Doc"), MarshalASTExpr(decl.Doc))
|
|
||||||
root.SetItem(c.Str("Parent"), MarshalASTExpr(decl.Parent))
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalASTExpr(t ast.Expr) *cjson.JSON {
|
|
||||||
if t == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
|
|
||||||
root := cjson.Object()
|
|
||||||
|
|
||||||
switch d := t.(type) {
|
|
||||||
case *ast.EnumType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("EnumType"))
|
|
||||||
items := cjson.Array()
|
|
||||||
for _, e := range d.Items {
|
|
||||||
items.AddItem(MarshalASTExpr(e))
|
|
||||||
}
|
|
||||||
root.SetItem(c.Str("Items"), items)
|
|
||||||
case *ast.EnumItem:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("EnumItem"))
|
|
||||||
root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name))
|
|
||||||
root.SetItem(c.Str("Value"), MarshalASTExpr(d.Value))
|
|
||||||
case *ast.RecordType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("RecordType"))
|
|
||||||
root.SetItem(c.Str("Tag"), numberField(uint(d.Tag)))
|
|
||||||
root.SetItem(c.Str("Fields"), MarshalASTExpr(d.Fields))
|
|
||||||
methods := cjson.Array()
|
|
||||||
for _, m := range d.Methods {
|
|
||||||
methods.AddItem(MarshalASTDecl(m))
|
|
||||||
}
|
|
||||||
root.SetItem(c.Str("Methods"), methods)
|
|
||||||
case *ast.FuncType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("FuncType"))
|
|
||||||
root.SetItem(c.Str("Params"), MarshalASTExpr(d.Params))
|
|
||||||
root.SetItem(c.Str("Ret"), MarshalASTExpr(d.Ret))
|
|
||||||
case *ast.FieldList:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("FieldList"))
|
|
||||||
root.SetItem(c.Str("List"), MarshalFieldList(d.List))
|
|
||||||
case *ast.Field:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("Field"))
|
|
||||||
root.SetItem(c.Str("Type"), MarshalASTExpr(d.Type))
|
|
||||||
root.SetItem(c.Str("Doc"), MarshalASTExpr(d.Doc))
|
|
||||||
root.SetItem(c.Str("Comment"), MarshalASTExpr(d.Comment))
|
|
||||||
root.SetItem(c.Str("IsStatic"), boolField(d.IsStatic))
|
|
||||||
root.SetItem(c.Str("Access"), numberField(uint(d.Access)))
|
|
||||||
root.SetItem(c.Str("Names"), MarshalIdentList(d.Names))
|
|
||||||
case *ast.Variadic:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("Variadic"))
|
|
||||||
case *ast.Ident:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("Ident"))
|
|
||||||
if d == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
root.SetItem(c.Str("Name"), stringField(d.Name))
|
|
||||||
case *ast.TagExpr:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("TagExpr"))
|
|
||||||
root.SetItem(c.Str("Name"), MarshalASTExpr(d.Name))
|
|
||||||
root.SetItem(c.Str("Tag"), numberField(uint(d.Tag)))
|
|
||||||
case *ast.BasicLit:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("BasicLit"))
|
|
||||||
root.SetItem(c.Str("Kind"), numberField(uint(d.Kind)))
|
|
||||||
root.SetItem(c.Str("Value"), stringField(d.Value))
|
|
||||||
case *ast.LvalueRefType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("LvalueRefType"))
|
|
||||||
root.SetItem(c.Str("X"), MarshalASTExpr(d.X))
|
|
||||||
case *ast.RvalueRefType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("RvalueRefType"))
|
|
||||||
root.SetItem(c.Str("X"), MarshalASTExpr(d.X))
|
|
||||||
case *ast.PointerType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("PointerType"))
|
|
||||||
root.SetItem(c.Str("X"), MarshalASTExpr(d.X))
|
|
||||||
case *ast.ArrayType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("ArrayType"))
|
|
||||||
root.SetItem(c.Str("Elt"), MarshalASTExpr(d.Elt))
|
|
||||||
root.SetItem(c.Str("Len"), MarshalASTExpr(d.Len))
|
|
||||||
case *ast.BuiltinType:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("BuiltinType"))
|
|
||||||
root.SetItem(c.Str("Kind"), numberField(uint(d.Kind)))
|
|
||||||
root.SetItem(c.Str("Flags"), numberField(uint(d.Flags)))
|
|
||||||
case *ast.Comment:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("Comment"))
|
|
||||||
if d == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
root.SetItem(c.Str("Text"), stringField(d.Text))
|
|
||||||
case *ast.CommentGroup:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("CommentGroup"))
|
|
||||||
if d == nil {
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
list := cjson.Array()
|
|
||||||
for _, c := range d.List {
|
|
||||||
list.AddItem(MarshalASTExpr(c))
|
|
||||||
}
|
|
||||||
root.SetItem(c.Str("List"), list)
|
|
||||||
case *ast.ScopingExpr:
|
|
||||||
root.SetItem(c.Str("_Type"), stringField("ScopingExpr"))
|
|
||||||
root.SetItem(c.Str("X"), MarshalASTExpr(d.X))
|
|
||||||
root.SetItem(c.Str("Parent"), MarshalASTExpr(d.Parent))
|
|
||||||
default:
|
|
||||||
return cjson.Null()
|
|
||||||
}
|
|
||||||
return root
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringField(s string) *cjson.JSON {
|
|
||||||
return cjson.String(c.AllocaCStr(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func numberField(n uint) *cjson.JSON {
|
|
||||||
return cjson.Number(float64(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
func boolField(b bool) *cjson.JSON {
|
|
||||||
if b {
|
|
||||||
return cjson.True()
|
|
||||||
}
|
|
||||||
return cjson.False()
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewContext(isCpp bool) *Context {
|
|
||||||
return &Context{
|
|
||||||
Files: make([]*FileEntry, 0),
|
|
||||||
IsCpp: isCpp,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Context) Output() *cjson.JSON {
|
|
||||||
return MarshalOutputASTFiles(p.Files)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessFiles processes the given files and adds them to the context
|
|
||||||
func (p *Context) ProcessFiles(files []string) error {
|
|
||||||
if debugParse {
|
|
||||||
fmt.Fprintln(os.Stderr, "ProcessFiles: files", files, "isCpp", p.IsCpp)
|
|
||||||
}
|
|
||||||
for _, file := range files {
|
|
||||||
if err := p.processFile(file); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse file and add it to the context,avoid duplicate parsing
|
|
||||||
func (p *Context) processFile(path string) error {
|
|
||||||
if debugParse {
|
|
||||||
fmt.Fprintln(os.Stderr, "processFile: path", path)
|
|
||||||
}
|
|
||||||
for _, entry := range p.Files {
|
|
||||||
if entry.Path == path {
|
|
||||||
if debugParse {
|
|
||||||
fmt.Fprintln(os.Stderr, "processFile: already parsed", path)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parsedFiles, err := p.parseFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to parse file: " + path)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Files = append(p.Files, parsedFiles...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Context) parseFile(path string) ([]*FileEntry, error) {
|
|
||||||
if debugParse {
|
|
||||||
fmt.Fprintln(os.Stderr, "parseFile: path", path)
|
|
||||||
}
|
|
||||||
converter, err := NewConverter(&clangutils.Config{
|
|
||||||
File: path,
|
|
||||||
Temp: false,
|
|
||||||
IsCpp: p.IsCpp,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to create converter " + path)
|
|
||||||
}
|
|
||||||
defer converter.Dispose()
|
|
||||||
|
|
||||||
files, err := converter.Convert()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return files, nil
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/args"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestParseArgs()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseArgs() {
|
|
||||||
fmt.Println("=== Test ParseArgs ===")
|
|
||||||
|
|
||||||
swflags := map[string]bool{
|
|
||||||
"--extract": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
input []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Basic flags",
|
|
||||||
input: []string{"-h", "-v", "-"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Config file",
|
|
||||||
input: []string{"lua.llcppg.cfg"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Extract with multiple args",
|
|
||||||
input: []string{"--extract", "file1.h", "file2.h", "-v"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Non-skippable flags",
|
|
||||||
input: []string{"--extract", "file1.h", "file2.h", "-out=true", "-cpp=true", "-v"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Mixed flags",
|
|
||||||
input: []string{"-v", "--extract", "file.h", "-out=true", "config.json"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Empty input",
|
|
||||||
input: []string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("Test case: %s\n", tc.name)
|
|
||||||
fmt.Printf("Input: %v\n", tc.input)
|
|
||||||
|
|
||||||
result, filteredArgs := args.ParseArgs(tc.input, swflags)
|
|
||||||
|
|
||||||
fmt.Printf("Help: %v\n", result.Help)
|
|
||||||
fmt.Printf("Verbose: %v\n", result.Verbose)
|
|
||||||
fmt.Printf("UseStdin: %v\n", result.UseStdin)
|
|
||||||
fmt.Printf("CfgFile: %s\n", result.CfgFile)
|
|
||||||
fmt.Printf("FilteredArgs: %v\n", filteredArgs)
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#stdout
|
|
||||||
=== Test ParseArgs ===
|
|
||||||
Test case: Basic flags
|
|
||||||
Input: [-h -v -]
|
|
||||||
Help: true
|
|
||||||
Verbose: true
|
|
||||||
UseStdin: true
|
|
||||||
CfgFile: llcppg.cfg
|
|
||||||
FilteredArgs: []
|
|
||||||
|
|
||||||
Test case: Config file
|
|
||||||
Input: [lua.llcppg.cfg]
|
|
||||||
Help: false
|
|
||||||
Verbose: false
|
|
||||||
UseStdin: false
|
|
||||||
CfgFile: lua.llcppg.cfg
|
|
||||||
FilteredArgs: []
|
|
||||||
|
|
||||||
Test case: Extract with multiple args
|
|
||||||
Input: [--extract file1.h file2.h -v]
|
|
||||||
Help: false
|
|
||||||
Verbose: true
|
|
||||||
UseStdin: false
|
|
||||||
CfgFile: llcppg.cfg
|
|
||||||
FilteredArgs: [--extract file1.h file2.h]
|
|
||||||
|
|
||||||
Test case: Non-skippable flags
|
|
||||||
Input: [--extract file1.h file2.h -out=true -cpp=true -v]
|
|
||||||
Help: false
|
|
||||||
Verbose: true
|
|
||||||
UseStdin: false
|
|
||||||
CfgFile: llcppg.cfg
|
|
||||||
FilteredArgs: [--extract file1.h file2.h -out=true -cpp=true]
|
|
||||||
|
|
||||||
Test case: Mixed flags
|
|
||||||
Input: [-v --extract file.h -out=true config.json]
|
|
||||||
Help: false
|
|
||||||
Verbose: true
|
|
||||||
UseStdin: false
|
|
||||||
CfgFile: config.json
|
|
||||||
FilteredArgs: [--extract file.h -out=true]
|
|
||||||
|
|
||||||
Test case: Empty input
|
|
||||||
Input: []
|
|
||||||
Help: false
|
|
||||||
Verbose: false
|
|
||||||
UseStdin: false
|
|
||||||
CfgFile: llcppg.cfg
|
|
||||||
FilteredArgs: []
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestClangUtil()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClangUtil() {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
content string
|
|
||||||
isTemp bool
|
|
||||||
isCpp bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "C Header File",
|
|
||||||
content: `
|
|
||||||
int test_function(int a, int b);
|
|
||||||
void another_function(void);
|
|
||||||
`,
|
|
||||||
isTemp: false,
|
|
||||||
isCpp: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "C++ Temp File",
|
|
||||||
content: `
|
|
||||||
class TestClass {
|
|
||||||
public:
|
|
||||||
void test_method();
|
|
||||||
static int static_method(float f);
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace TestNamespace {
|
|
||||||
void namespaced_function();
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
isTemp: true,
|
|
||||||
isCpp: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("=== Test Case: %s ===\n", tc.name)
|
|
||||||
|
|
||||||
var filePath string
|
|
||||||
var tempFile *os.File
|
|
||||||
if tc.isTemp {
|
|
||||||
filePath = tc.content
|
|
||||||
} else {
|
|
||||||
var err error
|
|
||||||
tempFile, err = os.CreateTemp("", "test_*.h")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to create temporary file: %v\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = tempFile.Write([]byte(tc.content))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to write to temporary file: %v\n", err)
|
|
||||||
tempFile.Close()
|
|
||||||
os.Remove(tempFile.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tempFile.Close()
|
|
||||||
filePath = tempFile.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &clangutils.Config{
|
|
||||||
File: filePath,
|
|
||||||
Temp: tc.isTemp,
|
|
||||||
IsCpp: tc.isCpp,
|
|
||||||
}
|
|
||||||
index, unit, err := clangutils.CreateTranslationUnit(config)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("CreateTranslationUnit failed: %v\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("CreateTranslationUnit succeeded")
|
|
||||||
|
|
||||||
cursor := unit.Cursor()
|
|
||||||
|
|
||||||
clangutils.VisitChildren(cursor, func(cursor, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
switch cursor.Kind {
|
|
||||||
case clang.CursorFunctionDecl, clang.CursorCXXMethod:
|
|
||||||
funcName := cursor.String()
|
|
||||||
fmt.Printf("Function/Method: %s\n", c.GoString(funcName.CStr()))
|
|
||||||
parts := clangutils.BuildScopingParts(cursor)
|
|
||||||
fmt.Printf("Scoping parts: %v\n", parts)
|
|
||||||
funcName.Dispose()
|
|
||||||
case clang.CursorClassDecl:
|
|
||||||
className := cursor.String()
|
|
||||||
fmt.Printf("Class: %s\n", c.GoString(className.CStr()))
|
|
||||||
className.Dispose()
|
|
||||||
case clang.CursorNamespace:
|
|
||||||
namespaceName := cursor.String()
|
|
||||||
fmt.Printf("Namespace: %s\n", c.GoString(namespaceName.CStr()))
|
|
||||||
namespaceName.Dispose()
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Recurse
|
|
||||||
})
|
|
||||||
index.Dispose()
|
|
||||||
unit.Dispose()
|
|
||||||
|
|
||||||
if !tc.isTemp && tempFile != nil {
|
|
||||||
os.Remove(tempFile.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#stdout
|
|
||||||
=== Test Case: C Header File ===
|
|
||||||
CreateTranslationUnit succeeded
|
|
||||||
Function/Method: test_function
|
|
||||||
Scoping parts: [test_function]
|
|
||||||
Function/Method: another_function
|
|
||||||
Scoping parts: [another_function]
|
|
||||||
|
|
||||||
=== Test Case: C++ Temp File ===
|
|
||||||
CreateTranslationUnit succeeded
|
|
||||||
Class: TestClass
|
|
||||||
Function/Method: test_method
|
|
||||||
Scoping parts: [TestClass test_method]
|
|
||||||
Function/Method: static_method
|
|
||||||
Scoping parts: [TestClass static_method]
|
|
||||||
Namespace: TestNamespace
|
|
||||||
Function/Method: namespaced_function
|
|
||||||
Scoping parts: [TestNamespace namespaced_function]
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,332 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config/cfgparse"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestGetConf()
|
|
||||||
TestParseLibs()
|
|
||||||
TestGenDylibPaths()
|
|
||||||
TestParseCFlags()
|
|
||||||
TestGenHeaderFilePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetConf() {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
input string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "SQLite configuration",
|
|
||||||
input: `{
|
|
||||||
"name": "sqlite",
|
|
||||||
"cflags": "-I/opt/homebrew/opt/sqlite/include",
|
|
||||||
"include": ["sqlite3.h"],
|
|
||||||
"libs": "-L/opt/homebrew/opt/sqlite/lib -lsqlite3",
|
|
||||||
"trimPrefixes": ["sqlite3_"],
|
|
||||||
"cplusplus": false
|
|
||||||
}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Lua configuration",
|
|
||||||
input: `{
|
|
||||||
"name": "lua",
|
|
||||||
"cflags": "-I/opt/homebrew/include/lua",
|
|
||||||
"include": ["lua.h"],
|
|
||||||
"libs": "-L/opt/homebrew/lib -llua -lm",
|
|
||||||
"trimPrefixes": ["lua_", "lua_"],
|
|
||||||
"cplusplus": false
|
|
||||||
}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Invalid JSON",
|
|
||||||
input: `{invalid json}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("=== Test case: %s ===\n", tc.name)
|
|
||||||
result, err := config.GetConf([]byte(tc.input))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error:", err.Error())
|
|
||||||
} else {
|
|
||||||
fmt.Println("Name:", result.Config.Name)
|
|
||||||
fmt.Println("CFlags:", result.Config.CFlags)
|
|
||||||
fmt.Println("Libs:", result.Config.Libs)
|
|
||||||
fmt.Println("Include:", strings.Join(result.Config.Include, ", "))
|
|
||||||
fmt.Println("TrimPrefixes:", strings.Join(result.Config.TrimPrefixes, ", "))
|
|
||||||
fmt.Println("Cplusplus:", result.Config.Cplusplus)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseLibs() {
|
|
||||||
fmt.Println("=== Test ParseLibs ===")
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
input string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Lua library",
|
|
||||||
input: "-L/opt/homebrew/lib -llua -lm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "SQLite library",
|
|
||||||
input: "-L/opt/homebrew/opt/sqlite/lib -lsqlite3",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "INIReader library",
|
|
||||||
input: "-L/opt/homebrew/Cellar/inih/58/lib -lINIReader",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Multiple library paths",
|
|
||||||
input: "-L/opt/homebrew/lib -L/usr/lib -llua",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "No valid library",
|
|
||||||
input: "-L/opt/homebrew/lib",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("Test case: %s\n", tc.name)
|
|
||||||
fmt.Printf("Input: %s\n", tc.input)
|
|
||||||
|
|
||||||
conf := cfgparse.ParseLibs(tc.input)
|
|
||||||
|
|
||||||
fmt.Println("Paths:", conf.Paths)
|
|
||||||
fmt.Println("Names:", conf.Names)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenDylibPaths() {
|
|
||||||
fmt.Println("=== Test GenDylibPaths ===")
|
|
||||||
|
|
||||||
tempDir := os.TempDir()
|
|
||||||
tempDefaultPath := filepath.Join(tempDir, "symblib")
|
|
||||||
affix := ".dylib"
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
affix = ".so"
|
|
||||||
}
|
|
||||||
err := os.MkdirAll(tempDefaultPath, 0755)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to create temp default path: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dylib1 := filepath.Join(tempDir, "libsymb1"+affix)
|
|
||||||
dylib2 := filepath.Join(tempDir, "libsymb2"+affix)
|
|
||||||
defaultDylib3 := filepath.Join(tempDefaultPath, "libsymb3"+affix)
|
|
||||||
|
|
||||||
os.Create(dylib1)
|
|
||||||
os.Create(dylib2)
|
|
||||||
os.Create(defaultDylib3)
|
|
||||||
defer os.Remove(dylib1)
|
|
||||||
defer os.Remove(dylib2)
|
|
||||||
defer os.Remove(defaultDylib3)
|
|
||||||
defer os.Remove(tempDefaultPath)
|
|
||||||
|
|
||||||
testCase := []struct {
|
|
||||||
name string
|
|
||||||
conf *cfgparse.Libs
|
|
||||||
defaultPaths []string
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "existing dylib",
|
|
||||||
conf: &cfgparse.Libs{
|
|
||||||
Names: []string{"symb1"},
|
|
||||||
Paths: []string{tempDir},
|
|
||||||
},
|
|
||||||
defaultPaths: []string{},
|
|
||||||
want: []string{dylib1},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "existing dylibs",
|
|
||||||
conf: &cfgparse.Libs{
|
|
||||||
Names: []string{"symb1", "symb2"},
|
|
||||||
Paths: []string{tempDir},
|
|
||||||
},
|
|
||||||
defaultPaths: []string{},
|
|
||||||
want: []string{dylib1, dylib2},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "existint default paths",
|
|
||||||
conf: &cfgparse.Libs{
|
|
||||||
Names: []string{"symb1", "symb3"},
|
|
||||||
Paths: []string{tempDir},
|
|
||||||
},
|
|
||||||
defaultPaths: []string{tempDefaultPath},
|
|
||||||
want: []string{dylib1, defaultDylib3},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "existint default paths & not found",
|
|
||||||
conf: &cfgparse.Libs{
|
|
||||||
Names: []string{"symb1", "symb3", "math"},
|
|
||||||
Paths: []string{tempDir},
|
|
||||||
},
|
|
||||||
defaultPaths: []string{tempDefaultPath},
|
|
||||||
want: []string{dylib1, defaultDylib3},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no existing dylib",
|
|
||||||
conf: &cfgparse.Libs{
|
|
||||||
Names: []string{"notexist"},
|
|
||||||
Paths: []string{tempDir},
|
|
||||||
},
|
|
||||||
want: []string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range testCase {
|
|
||||||
fmt.Printf("Test case: %s\n", tc.name)
|
|
||||||
paths, notFounds, err := tc.conf.GenDylibPaths(tc.defaultPaths)
|
|
||||||
|
|
||||||
if len(notFounds) > 0 {
|
|
||||||
fmt.Println("notFounds", notFounds)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, path := range paths {
|
|
||||||
found := false
|
|
||||||
for _, wantPath := range tc.want {
|
|
||||||
if path == wantPath {
|
|
||||||
found = true
|
|
||||||
fileName := filepath.Base(path)
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
fileName = strings.TrimSuffix(fileName, ".so")
|
|
||||||
} else {
|
|
||||||
fileName = strings.TrimSuffix(fileName, ".dylib")
|
|
||||||
}
|
|
||||||
fmt.Printf("Path %s is in the expected paths\n", fileName)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
fmt.Printf("Path %s is not in the expected paths\n", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseCFlags() {
|
|
||||||
fmt.Println("=== Test ParseCFlags ===")
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
input string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Single include path",
|
|
||||||
input: "-I/usr/include",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Multiple include paths",
|
|
||||||
input: "-I/usr/include -I/opt/homebrew/include",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Include paths mixed with other flags",
|
|
||||||
input: "-I/usr/include -DDEBUG -I/opt/local/include -Wall",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Empty input",
|
|
||||||
input: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("Test case: %s\n", tc.name)
|
|
||||||
fmt.Printf("Input: %s\n", tc.input)
|
|
||||||
|
|
||||||
conf := cfgparse.ParseCFlags(tc.input)
|
|
||||||
|
|
||||||
fmt.Println("Paths:", conf.Paths)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenHeaderFilePath() {
|
|
||||||
fmt.Println("=== Test GenHeaderFilePath ===")
|
|
||||||
|
|
||||||
tempDir := os.TempDir()
|
|
||||||
temDir2 := filepath.Join(tempDir, "include")
|
|
||||||
tempFile1 := filepath.Join(tempDir, "test1.h")
|
|
||||||
tempFile2 := filepath.Join(tempDir, "test2.h")
|
|
||||||
tempFile3 := filepath.Join(temDir2, "test3.h")
|
|
||||||
os.MkdirAll(temDir2, 0755)
|
|
||||||
os.Create(tempFile1)
|
|
||||||
os.Create(tempFile2)
|
|
||||||
os.Create(tempFile3)
|
|
||||||
defer os.Remove(tempFile1)
|
|
||||||
defer os.Remove(tempFile2)
|
|
||||||
defer os.Remove(tempFile3)
|
|
||||||
defer os.Remove(temDir2)
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
cflags string
|
|
||||||
files []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Valid files",
|
|
||||||
cflags: "-I" + tempDir,
|
|
||||||
files: []string{"test1.h", "test2.h"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Mixed existing and non-existing files",
|
|
||||||
cflags: "-I" + tempDir,
|
|
||||||
files: []string{"test1.h", "nonexistent.h"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Multiple include paths",
|
|
||||||
cflags: "-I" + tempDir + " -I" + temDir2,
|
|
||||||
files: []string{"test1.h", "test2.h", "test3.h"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "No existing files",
|
|
||||||
cflags: "-I" + tempDir,
|
|
||||||
files: []string{"nonexistent1.h", "nonexistent2.h"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Empty file list",
|
|
||||||
cflags: "-I/usr/include",
|
|
||||||
files: []string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("Test case: %s\n", tc.name)
|
|
||||||
fmt.Printf("Input files: %v\n", tc.files)
|
|
||||||
|
|
||||||
cflag := cfgparse.ParseCFlags(tc.cflags)
|
|
||||||
result, notFounds, err := cflag.GenHeaderFilePaths(tc.files)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error: %v\n", err)
|
|
||||||
}
|
|
||||||
if len(notFounds) > 0 {
|
|
||||||
fmt.Println("notFounds", notFounds)
|
|
||||||
}
|
|
||||||
if result != nil {
|
|
||||||
relativeResult := make([]string, len(result))
|
|
||||||
for i, path := range result {
|
|
||||||
relativeResult[i] = filepath.Base(path)
|
|
||||||
}
|
|
||||||
fmt.Printf("Output: %v\n", relativeResult)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
#stdout
|
|
||||||
=== Test case: SQLite configuration ===
|
|
||||||
Name: sqlite
|
|
||||||
CFlags: -I/opt/homebrew/opt/sqlite/include
|
|
||||||
Libs: -L/opt/homebrew/opt/sqlite/lib -lsqlite3
|
|
||||||
Include: sqlite3.h
|
|
||||||
TrimPrefixes: sqlite3_
|
|
||||||
Cplusplus: false
|
|
||||||
|
|
||||||
=== Test case: Lua configuration ===
|
|
||||||
Name: lua
|
|
||||||
CFlags: -I/opt/homebrew/include/lua
|
|
||||||
Libs: -L/opt/homebrew/lib -llua -lm
|
|
||||||
Include: lua.h
|
|
||||||
TrimPrefixes: lua_, lua_
|
|
||||||
Cplusplus: false
|
|
||||||
|
|
||||||
=== Test case: Invalid JSON ===
|
|
||||||
Error: failed to parse config
|
|
||||||
|
|
||||||
=== Test ParseLibs ===
|
|
||||||
Test case: Lua library
|
|
||||||
Input: -L/opt/homebrew/lib -llua -lm
|
|
||||||
Paths: [/opt/homebrew/lib]
|
|
||||||
Names: [lua m]
|
|
||||||
Test case: SQLite library
|
|
||||||
Input: -L/opt/homebrew/opt/sqlite/lib -lsqlite3
|
|
||||||
Paths: [/opt/homebrew/opt/sqlite/lib]
|
|
||||||
Names: [sqlite3]
|
|
||||||
Test case: INIReader library
|
|
||||||
Input: -L/opt/homebrew/Cellar/inih/58/lib -lINIReader
|
|
||||||
Paths: [/opt/homebrew/Cellar/inih/58/lib]
|
|
||||||
Names: [INIReader]
|
|
||||||
Test case: Multiple library paths
|
|
||||||
Input: -L/opt/homebrew/lib -L/usr/lib -llua
|
|
||||||
Paths: [/opt/homebrew/lib /usr/lib]
|
|
||||||
Names: [lua]
|
|
||||||
Test case: No valid library
|
|
||||||
Input: -L/opt/homebrew/lib
|
|
||||||
Paths: [/opt/homebrew/lib]
|
|
||||||
Names: []
|
|
||||||
=== Test GenDylibPaths ===
|
|
||||||
Test case: existing dylib
|
|
||||||
Path libsymb1 is in the expected paths
|
|
||||||
Test case: existing dylibs
|
|
||||||
Path libsymb1 is in the expected paths
|
|
||||||
Path libsymb2 is in the expected paths
|
|
||||||
Test case: existint default paths
|
|
||||||
Path libsymb1 is in the expected paths
|
|
||||||
Path libsymb3 is in the expected paths
|
|
||||||
Test case: existint default paths & not found
|
|
||||||
notFounds [math]
|
|
||||||
Path libsymb1 is in the expected paths
|
|
||||||
Path libsymb3 is in the expected paths
|
|
||||||
Test case: no existing dylib
|
|
||||||
notFounds [notexist]
|
|
||||||
Error: failed to find any libraries
|
|
||||||
=== Test ParseCFlags ===
|
|
||||||
Test case: Single include path
|
|
||||||
Input: -I/usr/include
|
|
||||||
Paths: [/usr/include]
|
|
||||||
Test case: Multiple include paths
|
|
||||||
Input: -I/usr/include -I/opt/homebrew/include
|
|
||||||
Paths: [/usr/include /opt/homebrew/include]
|
|
||||||
Test case: Include paths mixed with other flags
|
|
||||||
Input: -I/usr/include -DDEBUG -I/opt/local/include -Wall
|
|
||||||
Paths: [/usr/include /opt/local/include]
|
|
||||||
Test case: Empty input
|
|
||||||
Input:
|
|
||||||
Paths: []
|
|
||||||
=== Test GenHeaderFilePath ===
|
|
||||||
Test case: Valid files
|
|
||||||
Input files: [test1.h test2.h]
|
|
||||||
Output: [test1.h test2.h]
|
|
||||||
|
|
||||||
Test case: Mixed existing and non-existing files
|
|
||||||
Input files: [test1.h nonexistent.h]
|
|
||||||
notFounds [nonexistent.h]
|
|
||||||
Output: [test1.h]
|
|
||||||
|
|
||||||
Test case: Multiple include paths
|
|
||||||
Input files: [test1.h test2.h test3.h]
|
|
||||||
Output: [test1.h test2.h test3.h]
|
|
||||||
|
|
||||||
Test case: No existing files
|
|
||||||
Input files: [nonexistent1.h nonexistent2.h]
|
|
||||||
Error: failed to find any header files
|
|
||||||
notFounds [nonexistent1.h nonexistent2.h]
|
|
||||||
|
|
||||||
Test case: Empty file list
|
|
||||||
Input files: []
|
|
||||||
Error: failed to find any header files
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#stdout
|
|
||||||
=== Test NewSymbolProcessor ===
|
|
||||||
Before: No prefixes After: Prefixes: [lua_ luaL_]
|
|
||||||
|
|
||||||
=== Test RemovePrefix ===
|
|
||||||
Before: lua_closethread After: closethread
|
|
||||||
Before: luaL_checknumber After: checknumber
|
|
||||||
|
|
||||||
=== Test ToGoName ===
|
|
||||||
Before: lua_closethread After: Closethread
|
|
||||||
Before: luaL_checknumber After: Checknumber
|
|
||||||
Before: sqlite3_close_v2 After: CloseV2
|
|
||||||
Before: sqlite3_callback After: Callback
|
|
||||||
Before: GetReal After: GetReal
|
|
||||||
Before: GetBoolean After: GetBoolean
|
|
||||||
Before: INIReader After: Reader
|
|
||||||
|
|
||||||
=== Test GenMethodName ===
|
|
||||||
Before: Class: INIReader, Name: INIReader After: (*INIReader).Init
|
|
||||||
Before: Class: INIReader, Name: INIReader After: (*INIReader).Dispose
|
|
||||||
Before: Class: INIReader, Name: HasValue After: (*INIReader).HasValue
|
|
||||||
|
|
||||||
=== Test AddSuffix ===
|
|
||||||
Before: Class: INIReader, Method: INIReader After: (*Reader).Init
|
|
||||||
Before: Class: INIReader, Method: INIReader After: (*Reader).Init__1
|
|
||||||
Before: Class: INIReader, Method: ParseError After: (*Reader).ParseError
|
|
||||||
Before: Class: INIReader, Method: HasValue After: (*Reader).HasValue
|
|
||||||
|
|
||||||
=== Test Case: C++ Class with Methods ===
|
|
||||||
Parsed Symbols:
|
|
||||||
Symbol Map GoName: (*Reader).Init__1, ProtoName In HeaderFile: INIReader::INIReader(const char *, int), MangledName: _ZN9INIReaderC1EPKci
|
|
||||||
Symbol Map GoName: (*Reader).Init, ProtoName In HeaderFile: INIReader::INIReader(const int &), MangledName: _ZN9INIReaderC1ERKi
|
|
||||||
Symbol Map GoName: (*Reader).Dispose, ProtoName In HeaderFile: INIReader::~INIReader(), MangledName: _ZN9INIReaderD1Ev
|
|
||||||
Symbol Map GoName: (*Reader).ParseError, ProtoName In HeaderFile: INIReader::ParseError(), MangledName: _ZNK9INIReader10ParseErrorEv
|
|
||||||
|
|
||||||
=== Test Case: C Functions ===
|
|
||||||
Parsed Symbols:
|
|
||||||
Symbol Map GoName: Compare, ProtoName In HeaderFile: lua_compare(lua_State *, int, int, int), MangledName: lua_compare
|
|
||||||
Symbol Map GoName: Rawequal, ProtoName In HeaderFile: lua_rawequal(lua_State *, int, int), MangledName: lua_rawequal
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestNewSymbolProcessor()
|
|
||||||
TestRemovePrefix()
|
|
||||||
TestToGoName()
|
|
||||||
TestGenMethodName()
|
|
||||||
TestAddSuffix()
|
|
||||||
TestParseHeaderFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewSymbolProcessor() {
|
|
||||||
fmt.Println("=== Test NewSymbolProcessor ===")
|
|
||||||
process := parse.NewSymbolProcessor([]string{"lua_", "luaL_"})
|
|
||||||
fmt.Printf("Before: No prefixes After: Prefixes: %v\n", process.Prefixes)
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRemovePrefix() {
|
|
||||||
fmt.Println("=== Test RemovePrefix ===")
|
|
||||||
process := parse.NewSymbolProcessor([]string{"lua_", "luaL_"})
|
|
||||||
|
|
||||||
testCases := []string{"lua_closethread", "luaL_checknumber"}
|
|
||||||
|
|
||||||
for _, input := range testCases {
|
|
||||||
result := process.TrimPrefixes(input)
|
|
||||||
fmt.Printf("Before: %s After: %s\n", input, result)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestToGoName() {
|
|
||||||
fmt.Println("=== Test ToGoName ===")
|
|
||||||
process1 := parse.NewSymbolProcessor([]string{"lua_", "luaL_"})
|
|
||||||
process2 := parse.NewSymbolProcessor([]string{"sqlite3_", "sqlite3_"})
|
|
||||||
process3 := parse.NewSymbolProcessor([]string{"INI"})
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
processor *parse.SymbolProcessor
|
|
||||||
input string
|
|
||||||
}{
|
|
||||||
{process1, "lua_closethread"},
|
|
||||||
{process1, "luaL_checknumber"},
|
|
||||||
{process2, "sqlite3_close_v2"},
|
|
||||||
{process2, "sqlite3_callback"},
|
|
||||||
{process3, "GetReal"},
|
|
||||||
{process3, "GetBoolean"},
|
|
||||||
{process3, "INIReader"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
result := tc.processor.ToGoName(tc.input)
|
|
||||||
fmt.Printf("Before: %s After: %s\n", tc.input, result)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGenMethodName() {
|
|
||||||
fmt.Println("=== Test GenMethodName ===")
|
|
||||||
process := &parse.SymbolProcessor{}
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
class string
|
|
||||||
name string
|
|
||||||
isDestructor bool
|
|
||||||
}{
|
|
||||||
{"INIReader", "INIReader", false},
|
|
||||||
{"INIReader", "INIReader", true},
|
|
||||||
{"INIReader", "HasValue", false},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
input := fmt.Sprintf("Class: %s, Name: %s", tc.class, tc.name)
|
|
||||||
result := process.GenMethodName(tc.class, tc.name, tc.isDestructor)
|
|
||||||
fmt.Printf("Before: %s After: %s\n", input, result)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddSuffix() {
|
|
||||||
fmt.Println("=== Test AddSuffix ===")
|
|
||||||
process := parse.NewSymbolProcessor([]string{"INI"})
|
|
||||||
methods := []string{
|
|
||||||
"INIReader",
|
|
||||||
"INIReader",
|
|
||||||
"ParseError",
|
|
||||||
"HasValue",
|
|
||||||
}
|
|
||||||
for _, method := range methods {
|
|
||||||
goName := process.ToGoName(method)
|
|
||||||
className := process.ToGoName("INIReader")
|
|
||||||
methodName := process.GenMethodName(className, goName, false)
|
|
||||||
finalName := process.AddSuffix(methodName)
|
|
||||||
input := fmt.Sprintf("Class: INIReader, Method: %s", method)
|
|
||||||
fmt.Printf("Before: %s After: %s\n", input, finalName)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseHeaderFile() {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
content string
|
|
||||||
isCpp bool
|
|
||||||
prefixes []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "C++ Class with Methods",
|
|
||||||
content: `
|
|
||||||
class INIReader {
|
|
||||||
public:
|
|
||||||
INIReader(const std::string &filename);
|
|
||||||
INIReader(const char *buffer, size_t buffer_size);
|
|
||||||
~INIReader();
|
|
||||||
int ParseError() const;
|
|
||||||
private:
|
|
||||||
static std::string MakeKey(const std::string §ion, const std::string &name);
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
isCpp: true,
|
|
||||||
prefixes: []string{"INI"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "C Functions",
|
|
||||||
content: `
|
|
||||||
typedef struct lua_State lua_State;
|
|
||||||
int(lua_rawequal)(lua_State *L, int idx1, int idx2);
|
|
||||||
int(lua_compare)(lua_State *L, int idx1, int idx2, int op);
|
|
||||||
`,
|
|
||||||
isCpp: false,
|
|
||||||
prefixes: []string{"lua_"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("=== Test Case: %s ===\n", tc.name)
|
|
||||||
|
|
||||||
symbolMap, err := parse.ParseHeaderFile([]string{tc.content}, tc.prefixes, tc.isCpp, true)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error: %v\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Parsed Symbols:")
|
|
||||||
|
|
||||||
var keys []string
|
|
||||||
for key := range symbolMap {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
info := symbolMap[key]
|
|
||||||
fmt.Printf("Symbol Map GoName: %s, ProtoName In HeaderFile: %s, MangledName: %s\n", info.GoName, info.ProtoName, key)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#stdout
|
|
||||||
=== Test GetCommonSymbols ===
|
|
||||||
|
|
||||||
Test Case: Lua symbols
|
|
||||||
Common Symbols (4):
|
|
||||||
Mangle: lua_absindex, CPP: lua_absindex(lua_State *, int), Go: Absindex
|
|
||||||
Mangle: lua_arith, CPP: lua_arith(lua_State *, int), Go: Arith
|
|
||||||
Mangle: lua_atpanic, CPP: lua_atpanic(lua_State *, lua_CFunction), Go: Atpanic
|
|
||||||
Mangle: lua_callk, CPP: lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction), Go: Callk
|
|
||||||
|
|
||||||
Test Case: INIReader and Std library symbols
|
|
||||||
Common Symbols (3):
|
|
||||||
Mangle: _ZNK9INIReader12GetInteger64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_x, CPP: INIReader::GetInteger64(const std::string &, const std::string &, int64_t), Go: (*Reader).GetInteger64
|
|
||||||
Mangle: _ZNK9INIReader7GetRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_d, CPP: INIReader::GetReal(const std::string &, const std::string &, double), Go: (*Reader).GetReal
|
|
||||||
Mangle: _ZNK9INIReader10ParseErrorEv, CPP: INIReader::ParseError(), Go: (*Reader).ParseError
|
|
||||||
|
|
||||||
=== Test ReadExistingSymbolTable ===
|
|
||||||
Symbols read from the file:
|
|
||||||
Symbol Map GoName: (*Reader).Init__1, ProtoName In HeaderFile: INIReader::INIReader(const char *, size_t), MangledName: _ZN9INIReaderC1EPKcm
|
|
||||||
Symbol Map GoName: (*Reader).GetBoolean, ProtoName In HeaderFile: INIReader::GetBoolean(const std::string &, const std::string &, bool), MangledName: _ZNK9INIReader10GetBooleanERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_b
|
|
||||||
Symbol Map GoName: (*Reader).ParseError, ProtoName In HeaderFile: INIReader::ParseError(), MangledName: _ZNK9INIReader10ParseErrorEv
|
|
||||||
Havent existed symb file
|
|
||||||
|
|
||||||
=== Test GenSymbolTableData ===
|
|
||||||
[{
|
|
||||||
"mangle": "lua_absindex",
|
|
||||||
"c++": "lua_absindex(lua_State *, int)",
|
|
||||||
"go": "Absindex"
|
|
||||||
}, {
|
|
||||||
"mangle": "lua_arith",
|
|
||||||
"c++": "lua_arith(lua_State *, int)",
|
|
||||||
"go": "Arith"
|
|
||||||
}, {
|
|
||||||
"mangle": "lua_atpanic",
|
|
||||||
"c++": "lua_atpanic(lua_State *, lua_CFunction)",
|
|
||||||
"go": "Atpanic"
|
|
||||||
}, {
|
|
||||||
"mangle": "lua_callk",
|
|
||||||
"c++": "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)",
|
|
||||||
"go": "ModifiedCallk"
|
|
||||||
}]
|
|
||||||
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/types"
|
|
||||||
"github.com/goplus/llgo/xtool/nm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestGetCommonSymbols()
|
|
||||||
TestReadExistingSymbolTable()
|
|
||||||
TestGenSymbolTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetCommonSymbols() {
|
|
||||||
fmt.Println("=== Test GetCommonSymbols ===")
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
dylibSymbols []*nm.Symbol
|
|
||||||
headerSymbols map[string]*parse.SymbolInfo
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Lua symbols",
|
|
||||||
dylibSymbols: []*nm.Symbol{
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_absindex", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_arith", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_atpanic", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_callk", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_lib_nonexistent", false)},
|
|
||||||
},
|
|
||||||
headerSymbols: map[string]*parse.SymbolInfo{
|
|
||||||
"lua_absindex": {ProtoName: "lua_absindex(lua_State *, int)", GoName: "Absindex"},
|
|
||||||
"lua_arith": {ProtoName: "lua_arith(lua_State *, int)", GoName: "Arith"},
|
|
||||||
"lua_atpanic": {ProtoName: "lua_atpanic(lua_State *, lua_CFunction)", GoName: "Atpanic"},
|
|
||||||
"lua_callk": {ProtoName: "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)", GoName: "Callk"},
|
|
||||||
"lua_header_nonexistent": {ProtoName: "lua_header_nonexistent()", GoName: "HeaderNonexistent"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "INIReader and Std library symbols",
|
|
||||||
dylibSymbols: []*nm.Symbol{
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZNK9INIReader12GetInteger64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_x", true)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZNK9INIReader7GetRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_d", true)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZNK9INIReader10ParseErrorEv", true)},
|
|
||||||
},
|
|
||||||
headerSymbols: map[string]*parse.SymbolInfo{
|
|
||||||
"_ZNK9INIReader12GetInteger64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_x": {GoName: "(*Reader).GetInteger64", ProtoName: "INIReader::GetInteger64(const std::string &, const std::string &, int64_t)"},
|
|
||||||
"_ZNK9INIReader13GetUnsigned64ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_y": {GoName: "(*Reader).GetUnsigned64", ProtoName: "INIReader::GetUnsigned64(const std::string &, const std::string &, uint64_t)"},
|
|
||||||
"_ZNK9INIReader7GetRealERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_d": {GoName: "(*Reader).GetReal", ProtoName: "INIReader::GetReal(const std::string &, const std::string &, double)"},
|
|
||||||
"_ZNK9INIReader10ParseErrorEv": {GoName: "(*Reader).ParseError", ProtoName: "INIReader::ParseError()"},
|
|
||||||
"_ZNK9INIReader10GetBooleanERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_b": {GoName: "(*Reader).GetBoolean", ProtoName: "INIReader::GetBoolean(const std::string &, const std::string &, bool)"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("\nTest Case: %s\n", tc.name)
|
|
||||||
commonSymbols := symbol.GetCommonSymbols(tc.dylibSymbols, tc.headerSymbols)
|
|
||||||
fmt.Printf("Common Symbols (%d):\n", len(commonSymbols))
|
|
||||||
for _, sym := range commonSymbols {
|
|
||||||
fmt.Printf("Mangle: %s, CPP: %s, Go: %s\n", sym.Mangle, sym.CPP, sym.Go)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
func TestReadExistingSymbolTable() {
|
|
||||||
fmt.Println("=== Test ReadExistingSymbolTable ===")
|
|
||||||
|
|
||||||
tmpFile, err := os.CreateTemp("", "llcppg.symb.json")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to create temp file: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer os.Remove(tmpFile.Name())
|
|
||||||
|
|
||||||
testData := `[
|
|
||||||
{
|
|
||||||
"mangle": "_ZN9INIReaderC1EPKcm",
|
|
||||||
"c++": "INIReader::INIReader(const char *, size_t)",
|
|
||||||
"go": "(*Reader).Init__1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mangle": "_ZNK9INIReader10GetBooleanERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_b",
|
|
||||||
"c++": "INIReader::GetBoolean(const std::string &, const std::string &, bool)",
|
|
||||||
"go": "(*Reader).GetBoolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"mangle": "_ZNK9INIReader10ParseErrorEv",
|
|
||||||
"c++": "INIReader::ParseError()",
|
|
||||||
"go": "(*Reader).ParseError"
|
|
||||||
}
|
|
||||||
]`
|
|
||||||
if _, err := tmpFile.Write([]byte(testData)); err != nil {
|
|
||||||
fmt.Printf("Failed to write test data: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tmpFile.Close()
|
|
||||||
|
|
||||||
symbols, exist := symbol.ReadExistingSymbolTable(tmpFile.Name())
|
|
||||||
if !exist {
|
|
||||||
fmt.Printf("ReadExistingSymbolTable failed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Symbols read from the file:")
|
|
||||||
var keys []string
|
|
||||||
for key := range symbols {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
info := symbols[key]
|
|
||||||
fmt.Printf("Symbol Map GoName: %s, ProtoName In HeaderFile: %s, MangledName: %s\n",
|
|
||||||
info.Go, info.CPP, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, exist = symbol.ReadExistingSymbolTable("other.json")
|
|
||||||
if !exist {
|
|
||||||
fmt.Println("Havent existed symb file")
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
func TestGenSymbolTableData() {
|
|
||||||
fmt.Println("=== Test GenSymbolTableData ===")
|
|
||||||
|
|
||||||
commonSymbols := []*types.SymbolInfo{
|
|
||||||
{Mangle: "lua_absindex", CPP: "lua_absindex(lua_State *, int)", Go: "Absindex"},
|
|
||||||
{Mangle: "lua_arith", CPP: "lua_arith(lua_State *, int)", Go: "Arith"},
|
|
||||||
{Mangle: "lua_atpanic", CPP: "lua_atpanic(lua_State *, lua_CFunction)", Go: "Atpanic"},
|
|
||||||
{Mangle: "lua_callk", CPP: "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)", Go: "Callk"},
|
|
||||||
}
|
|
||||||
|
|
||||||
existingSymbols := map[string]types.SymbolInfo{
|
|
||||||
"lua_absindex": {Mangle: "lua_absindex", CPP: "lua_absindex(lua_State *, int)", Go: "Absindex"},
|
|
||||||
"lua_arith": {Mangle: "lua_arith", CPP: "lua_arith(lua_State *, int)", Go: "Arith"},
|
|
||||||
"lua_callk": {Mangle: "lua_callk", CPP: "lua_callk(lua_State *, int, int, lua_KContext, lua_KFunction)", Go: "ModifiedCallk"},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := symbol.GenSymbolTableData(commonSymbols, existingSymbols)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error generating symbol table data: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(string(data))
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
#stdout
|
|
||||||
=== Test Case: inireader ===
|
|
||||||
[{
|
|
||||||
"mangle": "_ZN9INIReaderC1EPKc",
|
|
||||||
"c++": "INIReader::INIReader(const char *)",
|
|
||||||
"go": "(*Reader).Init"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZN9INIReaderC1EPKcl",
|
|
||||||
"c++": "INIReader::INIReader(const char *, long)",
|
|
||||||
"go": "(*Reader).Init__1"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZN9INIReaderD1Ev",
|
|
||||||
"c++": "INIReader::~INIReader()",
|
|
||||||
"go": "(*Reader).Dispose"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZNK9INIReader10ParseErrorEv",
|
|
||||||
"c++": "INIReader::ParseError()",
|
|
||||||
"go": "(*Reader).ModifyedParseError"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZNK9INIReader3GetEPKcS1_S1_",
|
|
||||||
"c++": "INIReader::Get(const char *, const char *, const char *)",
|
|
||||||
"go": "(*Reader).Get"
|
|
||||||
}]
|
|
||||||
=== Test Case: lua ===
|
|
||||||
[{
|
|
||||||
"mangle": "lua_error",
|
|
||||||
"c++": "lua_error(lua_State *)",
|
|
||||||
"go": "Error"
|
|
||||||
}, {
|
|
||||||
"mangle": "lua_next",
|
|
||||||
"c++": "lua_next(lua_State *, int)",
|
|
||||||
"go": "Next"
|
|
||||||
}, {
|
|
||||||
"mangle": "lua_concat",
|
|
||||||
"c++": "lua_concat(lua_State *, int)",
|
|
||||||
"go": "Concat"
|
|
||||||
}, {
|
|
||||||
"mangle": "lua_stringtonumber",
|
|
||||||
"c++": "lua_stringtonumber(lua_State *, const char *)",
|
|
||||||
"go": "Stringtonumber"
|
|
||||||
}]
|
|
||||||
|
|
||||||
#stderr
|
|
||||||
|
|
||||||
#exit 0
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
|
||||||
"github.com/goplus/llgo/xtool/nm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
TestParseHeaderFile()
|
|
||||||
}
|
|
||||||
func TestParseHeaderFile() {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
content string
|
|
||||||
isCpp bool
|
|
||||||
prefixes []string
|
|
||||||
dylibSymbols []*nm.Symbol
|
|
||||||
symbFileContent string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "inireader",
|
|
||||||
content: `
|
|
||||||
#define INI_API __attribute__((visibility("default")))
|
|
||||||
class INIReader {
|
|
||||||
public:
|
|
||||||
__attribute__((visibility("default"))) explicit INIReader(const char *filename);
|
|
||||||
INI_API explicit INIReader(const char *buffer, long buffer_size);
|
|
||||||
~INIReader();
|
|
||||||
INI_API int ParseError() const;
|
|
||||||
INI_API const char * Get(const char *section, const char *name,
|
|
||||||
const char *default_value) const;
|
|
||||||
private:
|
|
||||||
static const char * MakeKey(const char *section, const char *name);
|
|
||||||
};
|
|
||||||
`,
|
|
||||||
isCpp: true,
|
|
||||||
prefixes: []string{"INI"},
|
|
||||||
dylibSymbols: []*nm.Symbol{
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZN9INIReaderC1EPKc", true)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZN9INIReaderC1EPKcl", true)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZN9INIReaderD1Ev", true)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZNK9INIReader10ParseErrorEv", true)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("ZNK9INIReader3GetEPKcS1_S1_", true)},
|
|
||||||
},
|
|
||||||
symbFileContent: `
|
|
||||||
[{
|
|
||||||
"mangle": "_ZN9INIReaderC1EPKc",
|
|
||||||
"c++": "INIReader::INIReader(const char *)",
|
|
||||||
"go": "(*Reader).Init"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZN9INIReaderC1EPKcl",
|
|
||||||
"c++": "INIReader::INIReader(const char *, long)",
|
|
||||||
"go": "(*Reader).Init__1"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZN9INIReaderD1Ev",
|
|
||||||
"c++": "INIReader::~INIReader()",
|
|
||||||
"go": "(*Reader).Dispose"
|
|
||||||
}, {
|
|
||||||
"mangle": "_ZNK9INIReader10ParseErrorEv",
|
|
||||||
"c++": "INIReader::ParseError()",
|
|
||||||
"go": "(*Reader).ModifyedParseError"
|
|
||||||
}]`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "lua",
|
|
||||||
content: `
|
|
||||||
typedef struct lua_State lua_State;
|
|
||||||
|
|
||||||
LUA_API int(lua_error)(lua_State *L);
|
|
||||||
|
|
||||||
LUA_API int(lua_next)(lua_State *L, int idx);
|
|
||||||
|
|
||||||
LUA_API void(lua_concat)(lua_State *L, int n);
|
|
||||||
LUA_API void(lua_len)(lua_State *L, int idx);
|
|
||||||
|
|
||||||
LUA_API long unsigned int(lua_stringtonumber)(lua_State *L, const char *s);
|
|
||||||
|
|
||||||
LUA_API void(lua_setallocf)(lua_State *L, lua_Alloc f, void *ud);
|
|
||||||
|
|
||||||
LUA_API void(lua_toclose)(lua_State *L, int idx);
|
|
||||||
LUA_API void(lua_closeslot)(lua_State *L, int idx);
|
|
||||||
`,
|
|
||||||
isCpp: false,
|
|
||||||
prefixes: []string{"lua_"},
|
|
||||||
dylibSymbols: []*nm.Symbol{
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_error", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_next", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_concat", false)},
|
|
||||||
{Name: symbol.AddSymbolPrefixUnder("lua_stringtonumber", false)},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
fmt.Printf("=== Test Case: %s ===\n", tc.name)
|
|
||||||
headerSymbolMap, err := parse.ParseHeaderFile([]string{tc.content}, tc.prefixes, tc.isCpp, true)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error:", err)
|
|
||||||
}
|
|
||||||
tmpFile, err := os.CreateTemp("", "llcppg.symb.json")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to create temp file: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tmpFile.Write([]byte(tc.symbFileContent))
|
|
||||||
symbolData, err := symbol.GenerateAndUpdateSymbolTable(tc.dylibSymbols, headerSymbolMap, tmpFile.Name())
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error:", err)
|
|
||||||
}
|
|
||||||
fmt.Println(string(symbolData))
|
|
||||||
os.Remove(tmpFile.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package args
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
type Args struct {
|
|
||||||
Help bool
|
|
||||||
Verbose bool
|
|
||||||
UseStdin bool
|
|
||||||
CfgFile string
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseArgs(args []string, swflags map[string]bool) (*Args, []string) {
|
|
||||||
result := &Args{}
|
|
||||||
filteredArgs := []string{}
|
|
||||||
for i := 0; i < len(args); i++ {
|
|
||||||
arg := args[i]
|
|
||||||
if strings.HasPrefix(arg, "-") {
|
|
||||||
switch arg {
|
|
||||||
case "-h", "--help":
|
|
||||||
result.Help = true
|
|
||||||
continue
|
|
||||||
case "-v":
|
|
||||||
result.Verbose = true
|
|
||||||
continue
|
|
||||||
case "-":
|
|
||||||
result.UseStdin = true
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
if hasArg, ok := swflags[arg]; ok {
|
|
||||||
if hasArg {
|
|
||||||
filteredArgs = append(filteredArgs, arg)
|
|
||||||
for i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
|
|
||||||
filteredArgs = append(filteredArgs, args[i+1])
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filteredArgs = append(filteredArgs, arg)
|
|
||||||
}
|
|
||||||
} else if result.CfgFile == "" {
|
|
||||||
result.CfgFile = arg
|
|
||||||
} else {
|
|
||||||
filteredArgs = append(filteredArgs, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if result.CfgFile == "" {
|
|
||||||
result.CfgFile = "llcppg.cfg"
|
|
||||||
}
|
|
||||||
return result, filteredArgs
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
package clangutils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
File string
|
|
||||||
Temp bool
|
|
||||||
Args []string
|
|
||||||
IsCpp bool
|
|
||||||
Index *clang.Index
|
|
||||||
}
|
|
||||||
|
|
||||||
type Visitor func(cursor, parent clang.Cursor) clang.ChildVisitResult
|
|
||||||
|
|
||||||
const TEMP_FILE = "temp.h"
|
|
||||||
|
|
||||||
func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) {
|
|
||||||
// default use the c/c++ standard of clang; c:gnu17 c++:gnu++17
|
|
||||||
// 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(allArgs))
|
|
||||||
for i, arg := range allArgs {
|
|
||||||
cArgs[i] = c.AllocaCStr(arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
var index *clang.Index
|
|
||||||
if config.Index != nil {
|
|
||||||
index = config.Index
|
|
||||||
} else {
|
|
||||||
index = clang.CreateIndex(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var unit *clang.TranslationUnit
|
|
||||||
|
|
||||||
if config.Temp {
|
|
||||||
content := c.AllocaCStr(config.File)
|
|
||||||
tempFile := &clang.UnsavedFile{
|
|
||||||
Filename: c.Str(TEMP_FILE),
|
|
||||||
Contents: content,
|
|
||||||
Length: c.Ulong(c.Strlen(content)),
|
|
||||||
}
|
|
||||||
|
|
||||||
unit = index.ParseTranslationUnit(
|
|
||||||
tempFile.Filename,
|
|
||||||
unsafe.SliceData(cArgs), c.Int(len(cArgs)),
|
|
||||||
tempFile, 1,
|
|
||||||
clang.DetailedPreprocessingRecord,
|
|
||||||
)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
cFile := c.AllocaCStr(config.File)
|
|
||||||
unit = index.ParseTranslationUnit(
|
|
||||||
cFile,
|
|
||||||
unsafe.SliceData(cArgs), c.Int(len(cArgs)),
|
|
||||||
nil, 0,
|
|
||||||
clang.DetailedPreprocessingRecord,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if unit == nil {
|
|
||||||
return nil, nil, errors.New("failed to parse translation unit")
|
|
||||||
}
|
|
||||||
|
|
||||||
return index, unit, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLocation(loc clang.SourceLocation) (file clang.File, line c.Uint, column c.Uint, offset c.Uint) {
|
|
||||||
loc.SpellingLocation(&file, &line, &column, &offset)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traverse up the semantic parents
|
|
||||||
func BuildScopingParts(cursor clang.Cursor) []string {
|
|
||||||
var parts []string
|
|
||||||
for cursor.IsNull() != 1 && cursor.Kind != clang.CursorTranslationUnit {
|
|
||||||
name := cursor.String()
|
|
||||||
qualified := c.GoString(name.CStr())
|
|
||||||
parts = append([]string{qualified}, parts...)
|
|
||||||
cursor = cursor.SemanticParent()
|
|
||||||
name.Dispose()
|
|
||||||
}
|
|
||||||
return parts
|
|
||||||
}
|
|
||||||
|
|
||||||
func VisitChildren(cursor clang.Cursor, fn Visitor) c.Uint {
|
|
||||||
return clang.VisitChildren(cursor, func(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
|
|
||||||
cfn := *(*Visitor)(clientData)
|
|
||||||
return cfn(cursor, parent)
|
|
||||||
}, unsafe.Pointer(&fn))
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
package cfgparse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Note: This package is not placed under the 'config' package because 'config'
|
|
||||||
// depends on 'cjson'. The parsing of Libs and cflags is intended to be usable
|
|
||||||
// by both llgo and go, without introducing additional dependencies.
|
|
||||||
|
|
||||||
type Libs struct {
|
|
||||||
Paths []string // Dylib Path
|
|
||||||
Names []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CFlags struct {
|
|
||||||
Paths []string // Include Path
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseLibs(libs string) *Libs {
|
|
||||||
parts := strings.Fields(libs)
|
|
||||||
lbs := &Libs{}
|
|
||||||
for _, part := range parts {
|
|
||||||
if strings.HasPrefix(part, "-L") {
|
|
||||||
lbs.Paths = append(lbs.Paths, part[2:])
|
|
||||||
} else if strings.HasPrefix(part, "-l") {
|
|
||||||
lbs.Names = append(lbs.Names, part[2:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lbs
|
|
||||||
}
|
|
||||||
|
|
||||||
// searches for each library name in the provided paths and default paths,
|
|
||||||
// appending the appropriate file extension (.dylib for macOS, .so for Linux).
|
|
||||||
//
|
|
||||||
// Example: For "-L/opt/homebrew/lib -llua -lm":
|
|
||||||
// - It will search for liblua.dylib (on macOS) or liblua.so (on Linux)
|
|
||||||
// - System libs like -lm are ignored and included in notFound
|
|
||||||
//
|
|
||||||
// So error is returned if no libraries found at all.
|
|
||||||
func (l *Libs) GenDylibPaths(defaultPaths []string) ([]string, []string, error) {
|
|
||||||
var foundPaths []string
|
|
||||||
var notFound []string
|
|
||||||
affix := ".dylib"
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
affix = ".so"
|
|
||||||
}
|
|
||||||
searchPaths := append(l.Paths, defaultPaths...)
|
|
||||||
for _, name := range l.Names {
|
|
||||||
var foundPath string
|
|
||||||
for _, path := range searchPaths {
|
|
||||||
dylibPath := filepath.Join(path, "lib"+name+affix)
|
|
||||||
if _, err := os.Stat(dylibPath); err == nil {
|
|
||||||
foundPath = dylibPath
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if foundPath != "" {
|
|
||||||
foundPaths = append(foundPaths, foundPath)
|
|
||||||
} else {
|
|
||||||
notFound = append(notFound, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(foundPaths) == 0 {
|
|
||||||
return nil, notFound, fmt.Errorf("failed to find any libraries")
|
|
||||||
}
|
|
||||||
return foundPaths, notFound, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Conf struct {
|
|
||||||
*cjson.JSON
|
|
||||||
*types.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConf(data []byte) (Conf, error) {
|
|
||||||
parsedConf := cjson.ParseBytes(data)
|
|
||||||
if parsedConf == nil {
|
|
||||||
return Conf{}, errors.New("failed to parse config")
|
|
||||||
}
|
|
||||||
|
|
||||||
config := &types.Config{
|
|
||||||
Name: GetStringItem(parsedConf, "name", ""),
|
|
||||||
CFlags: GetStringItem(parsedConf, "cflags", ""),
|
|
||||||
Libs: GetStringItem(parsedConf, "libs", ""),
|
|
||||||
Include: GetStringArrayItem(parsedConf, "include"),
|
|
||||||
TrimPrefixes: GetStringArrayItem(parsedConf, "trimPrefixes"),
|
|
||||||
Cplusplus: GetBoolItem(parsedConf, "cplusplus"),
|
|
||||||
}
|
|
||||||
|
|
||||||
return Conf{
|
|
||||||
JSON: parsedConf,
|
|
||||||
Config: config,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetString(obj *cjson.JSON) (value string) {
|
|
||||||
str := obj.GetStringValue()
|
|
||||||
return unsafe.String((*byte)(unsafe.Pointer(str)), c.Strlen(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStringItem(obj *cjson.JSON, key string, defval string) (value string) {
|
|
||||||
item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key))
|
|
||||||
if item == nil {
|
|
||||||
return defval
|
|
||||||
}
|
|
||||||
return GetString(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStringArrayItem(obj *cjson.JSON, key string) (value []string) {
|
|
||||||
item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key))
|
|
||||||
if item == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
value = make([]string, item.GetArraySize())
|
|
||||||
for i := range value {
|
|
||||||
value[i] = GetString(item.GetArrayItem(c.Int(i)))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBoolItem(obj *cjson.JSON, key string) bool {
|
|
||||||
item := obj.GetObjectItemCaseSensitive(c.AllocaCStr(key))
|
|
||||||
if item == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if item.IsBool() != 0 {
|
|
||||||
return item.IsTrue() != 0
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/args"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config/cfgparse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/symbol"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
symbFile := "llcppg.symb.json"
|
|
||||||
|
|
||||||
ags, _ := args.ParseArgs(os.Args[1:], nil)
|
|
||||||
|
|
||||||
var data []byte
|
|
||||||
var err error
|
|
||||||
if ags.UseStdin {
|
|
||||||
data, err = io.ReadAll(os.Stdin)
|
|
||||||
} else {
|
|
||||||
data, err = os.ReadFile(ags.CfgFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
check(err)
|
|
||||||
conf, err := config.GetConf(data)
|
|
||||||
check(err)
|
|
||||||
defer conf.Delete()
|
|
||||||
|
|
||||||
if ags.Verbose {
|
|
||||||
symbol.SetDebug(symbol.DbgFlagAll)
|
|
||||||
if ags.UseStdin {
|
|
||||||
fmt.Println("Config From Stdin")
|
|
||||||
} else {
|
|
||||||
fmt.Println("Config From File", ags.CfgFile)
|
|
||||||
}
|
|
||||||
fmt.Println("Name:", conf.Name)
|
|
||||||
fmt.Println("CFlags:", conf.CFlags)
|
|
||||||
fmt.Println("Libs:", conf.Libs)
|
|
||||||
fmt.Println("Include:", conf.Include)
|
|
||||||
fmt.Println("TrimPrefixes:", conf.TrimPrefixes)
|
|
||||||
fmt.Println("Cplusplus:", conf.Cplusplus)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Failed to parse config file:", ags.CfgFile)
|
|
||||||
}
|
|
||||||
symbols, err := symbol.ParseDylibSymbols(conf.Libs)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
cflag := cfgparse.ParseCFlags(conf.CFlags)
|
|
||||||
filepaths, notFounds, err := cflag.GenHeaderFilePaths(conf.Include)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
if ags.Verbose {
|
|
||||||
fmt.Println("header file paths", filepaths)
|
|
||||||
if len(notFounds) > 0 {
|
|
||||||
fmt.Println("not found header files", notFounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
headerInfos, err := parse.ParseHeaderFile(filepaths, conf.TrimPrefixes, conf.Cplusplus, false)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
symbolData, err := symbol.GenerateAndUpdateSymbolTable(symbols, headerInfos, symbFile)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
err = os.WriteFile(symbFile, symbolData, 0644)
|
|
||||||
check(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func check(err error) {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
package parse
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/clang"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/clangutils"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SymbolInfo struct {
|
|
||||||
GoName string
|
|
||||||
ProtoName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SymbolProcessor struct {
|
|
||||||
Prefixes []string
|
|
||||||
SymbolMap map[string]*SymbolInfo
|
|
||||||
CurrentFile string
|
|
||||||
NameCounts map[string]int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSymbolProcessor(Prefixes []string) *SymbolProcessor {
|
|
||||||
return &SymbolProcessor{
|
|
||||||
Prefixes: Prefixes,
|
|
||||||
SymbolMap: make(map[string]*SymbolInfo),
|
|
||||||
NameCounts: make(map[string]int),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) setCurrentFile(filename string) {
|
|
||||||
p.CurrentFile = filename
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) TrimPrefixes(str string) string {
|
|
||||||
for _, prefix := range p.Prefixes {
|
|
||||||
if strings.HasPrefix(str, prefix) {
|
|
||||||
return strings.TrimPrefix(str, prefix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
func toTitle(s string) string {
|
|
||||||
if s == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return strings.ToUpper(s[:1]) + (s[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func toUpperCamelCase(originName string) string {
|
|
||||||
if originName == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
subs := strings.Split(string(originName), "_")
|
|
||||||
name := ""
|
|
||||||
for _, sub := range subs {
|
|
||||||
name += toTitle(sub)
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. remove prefix from config
|
|
||||||
// 2. convert to camel case
|
|
||||||
func (p *SymbolProcessor) ToGoName(name string) string {
|
|
||||||
return toUpperCamelCase(p.TrimPrefixes(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) GenMethodName(class, name string, isDestructor bool) string {
|
|
||||||
prefix := "(*" + class + ")."
|
|
||||||
if isDestructor {
|
|
||||||
return prefix + "Dispose"
|
|
||||||
}
|
|
||||||
if class == name {
|
|
||||||
return prefix + "Init"
|
|
||||||
}
|
|
||||||
return prefix + name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) genGoName(cursor clang.Cursor) string {
|
|
||||||
funcName := cursor.String()
|
|
||||||
defer funcName.Dispose()
|
|
||||||
|
|
||||||
originName := c.GoString(funcName.CStr())
|
|
||||||
isDestructor := cursor.Kind == clang.CursorDestructor
|
|
||||||
var convertedName string
|
|
||||||
if isDestructor {
|
|
||||||
convertedName = p.ToGoName(originName[1:])
|
|
||||||
} else {
|
|
||||||
convertedName = p.ToGoName(originName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if parent := cursor.SemanticParent(); parent.Kind == clang.CursorClassDecl {
|
|
||||||
parentName := parent.String()
|
|
||||||
defer parentName.Dispose()
|
|
||||||
class := p.ToGoName(c.GoString(parentName.CStr()))
|
|
||||||
return p.AddSuffix(p.GenMethodName(class, convertedName, isDestructor))
|
|
||||||
}
|
|
||||||
return p.AddSuffix(convertedName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) genProtoName(cursor clang.Cursor) string {
|
|
||||||
displayName := cursor.DisplayName()
|
|
||||||
defer displayName.Dispose()
|
|
||||||
|
|
||||||
scopingParts := clangutils.BuildScopingParts(cursor.SemanticParent())
|
|
||||||
|
|
||||||
var builder strings.Builder
|
|
||||||
for _, part := range scopingParts {
|
|
||||||
builder.WriteString(part)
|
|
||||||
builder.WriteString("::")
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WriteString(c.GoString(displayName.CStr()))
|
|
||||||
return builder.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) AddSuffix(name string) string {
|
|
||||||
p.NameCounts[name]++
|
|
||||||
if count := p.NameCounts[name]; count > 1 {
|
|
||||||
return name + "__" + strconv.Itoa(count-1)
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) collectFuncInfo(cursor clang.Cursor) {
|
|
||||||
symbol := cursor.Mangling()
|
|
||||||
defer symbol.Dispose()
|
|
||||||
|
|
||||||
// On Linux, C++ symbols typically have one leading underscore
|
|
||||||
// On macOS, C++ symbols may have two leading underscores
|
|
||||||
// For consistency, we remove the first leading underscore on macOS
|
|
||||||
symbolName := c.GoString(symbol.CStr())
|
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
symbolName = strings.TrimPrefix(symbolName, "_")
|
|
||||||
}
|
|
||||||
p.SymbolMap[symbolName] = &SymbolInfo{
|
|
||||||
GoName: p.genGoName(cursor),
|
|
||||||
ProtoName: p.genProtoName(cursor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *SymbolProcessor) visitTop(cursor, parent clang.Cursor) clang.ChildVisitResult {
|
|
||||||
switch cursor.Kind {
|
|
||||||
case clang.CursorNamespace, clang.CursorClassDecl:
|
|
||||||
clangutils.VisitChildren(cursor, p.visitTop)
|
|
||||||
case clang.CursorCXXMethod, clang.CursorFunctionDecl, clang.CursorConstructor, clang.CursorDestructor:
|
|
||||||
loc := cursor.Location()
|
|
||||||
file, _, _, _ := clangutils.GetLocation(loc)
|
|
||||||
filename := file.FileName()
|
|
||||||
defer filename.Dispose()
|
|
||||||
|
|
||||||
isCurrentFile := c.Strcmp(filename.CStr(), c.AllocaCStr(p.CurrentFile)) == 0
|
|
||||||
isPublicMethod := (cursor.CXXAccessSpecifier() == clang.CXXPublic) && cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor
|
|
||||||
|
|
||||||
if isCurrentFile && (cursor.Kind == clang.CursorFunctionDecl || isPublicMethod) {
|
|
||||||
p.collectFuncInfo(cursor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clang.ChildVisit_Continue
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseHeaderFile(files []string, Prefixes []string, isCpp bool, isTemp bool) (map[string]*SymbolInfo, error) {
|
|
||||||
processer := NewSymbolProcessor(Prefixes)
|
|
||||||
index := clang.CreateIndex(0, 0)
|
|
||||||
for _, file := range files {
|
|
||||||
_, unit, err := clangutils.CreateTranslationUnit(&clangutils.Config{
|
|
||||||
File: file,
|
|
||||||
Temp: isTemp,
|
|
||||||
IsCpp: isCpp,
|
|
||||||
Index: index,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Unable to parse translation unit for file " + file)
|
|
||||||
}
|
|
||||||
cursor := unit.Cursor()
|
|
||||||
if isTemp {
|
|
||||||
processer.setCurrentFile(clangutils.TEMP_FILE)
|
|
||||||
} else {
|
|
||||||
processer.setCurrentFile(file)
|
|
||||||
}
|
|
||||||
clangutils.VisitChildren(cursor, processer.visitTop)
|
|
||||||
unit.Dispose()
|
|
||||||
}
|
|
||||||
index.Dispose()
|
|
||||||
return processer.SymbolMap, nil
|
|
||||||
}
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
package symbol
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/goplus/llgo/c"
|
|
||||||
"github.com/goplus/llgo/c/cjson"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/config/cfgparse"
|
|
||||||
"github.com/goplus/llgo/chore/_xtool/llcppsymg/parse"
|
|
||||||
"github.com/goplus/llgo/chore/llcppg/types"
|
|
||||||
"github.com/goplus/llgo/xtool/nm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type dbgFlags = int
|
|
||||||
|
|
||||||
const (
|
|
||||||
DbgSymbol dbgFlags = 1 << iota
|
|
||||||
DbgFlagAll = DbgSymbol
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
debugSymbol bool
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetDebug(dbgFlags dbgFlags) {
|
|
||||||
debugSymbol = (dbgFlags & DbgSymbol) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseDylibSymbols parses symbols from dynamic libraries specified in the lib string.
|
|
||||||
// It handles multiple libraries (e.g., -L/opt/homebrew/lib -llua -lm) and returns
|
|
||||||
// symbols if at least one library is successfully parsed. Errors from inaccessible
|
|
||||||
// libraries (like standard libs) are logged as warnings.
|
|
||||||
//
|
|
||||||
// Returns symbols and nil error if any symbols are found, or nil and error if none found.
|
|
||||||
func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("ParseDylibSymbols:from", lib)
|
|
||||||
}
|
|
||||||
sysPaths := getSysLibPaths()
|
|
||||||
lbs := cfgparse.ParseLibs(lib)
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("ParseDylibSymbols:LibConfig Parse To")
|
|
||||||
fmt.Println("libs.Names: ", lbs.Names)
|
|
||||||
fmt.Println("libs.Paths: ", lbs.Paths)
|
|
||||||
}
|
|
||||||
dylibPaths, notFounds, err := lbs.GenDylibPaths(sysPaths)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to generate some dylib paths: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("ParseDylibSymbols:dylibPaths", dylibPaths)
|
|
||||||
if len(notFounds) > 0 {
|
|
||||||
fmt.Println("ParseDylibSymbols:not found libname", notFounds)
|
|
||||||
} else {
|
|
||||||
fmt.Println("ParseDylibSymbols:every library is found")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var symbols []*nm.Symbol
|
|
||||||
var parseErrors []string
|
|
||||||
|
|
||||||
for _, dylibPath := range dylibPaths {
|
|
||||||
if _, err := os.Stat(dylibPath); err != nil {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Printf("ParseDylibSymbols:Failed to access dylib %s: %v\n", dylibPath, err)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err := nm.New("").List(dylibPath)
|
|
||||||
if err != nil {
|
|
||||||
parseErrors = append(parseErrors, fmt.Sprintf("ParseDylibSymbols:Failed to list symbols in dylib %s: %v", dylibPath, err))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range files {
|
|
||||||
symbols = append(symbols, file.Symbols...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(symbols) > 0 {
|
|
||||||
if debugSymbol {
|
|
||||||
if len(parseErrors) > 0 {
|
|
||||||
fmt.Printf("ParseDylibSymbols:Some libraries could not be parsed: %v\n", parseErrors)
|
|
||||||
}
|
|
||||||
fmt.Println("ParseDylibSymbols:", len(symbols), "symbols")
|
|
||||||
}
|
|
||||||
return symbols, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("no symbols found in any dylib. Errors: %v", parseErrors)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSysLibPaths() []string {
|
|
||||||
var paths []string
|
|
||||||
if runtime.GOOS == "linux" {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("getSysLibPaths:find sys lib path from linux")
|
|
||||||
}
|
|
||||||
paths = []string{
|
|
||||||
"/usr/lib",
|
|
||||||
"/usr/local/lib",
|
|
||||||
}
|
|
||||||
paths = append(paths, getPath("/etc/ld.so.conf")...)
|
|
||||||
if debugSymbol && len(paths) == 0 {
|
|
||||||
fmt.Println("getSysLibPaths:/etc/ld.so.conf havent find any path")
|
|
||||||
}
|
|
||||||
confd := "/etc/ld.so.conf.d"
|
|
||||||
dir, err := os.Stat(confd)
|
|
||||||
if err != nil || !dir.IsDir() {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("getSysLibPaths:/etc/ld.so.conf.d not found or not dir")
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
// todo(zzy) : wait llgo os.ReadDir support
|
|
||||||
// files, err := os.ReadDir(confd)
|
|
||||||
// if err == nil {
|
|
||||||
// for _, file := range files {
|
|
||||||
// filepath := filepath.Join(confd, file.Name())
|
|
||||||
// paths = append(paths, getPath(filepath)...)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPath(file string) []string {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("getPath:from", file)
|
|
||||||
}
|
|
||||||
var paths []string
|
|
||||||
content, err := os.ReadFile(file)
|
|
||||||
if err != nil {
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
lines := strings.Split(string(content), "\n")
|
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
if line != "" && !strings.HasPrefix(line, "#") {
|
|
||||||
if file, err := os.Stat(line); err == nil && file.IsDir() {
|
|
||||||
paths = append(paths, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
// finds the intersection of symbols from the dynamic library's symbol table and the symbols parsed from header files.
|
|
||||||
// It returns a list of symbols that can be externally linked.
|
|
||||||
func GetCommonSymbols(dylibSymbols []*nm.Symbol, headerSymbols map[string]*parse.SymbolInfo) []*types.SymbolInfo {
|
|
||||||
var commonSymbols []*types.SymbolInfo
|
|
||||||
for _, dylibSym := range dylibSymbols {
|
|
||||||
symName := dylibSym.Name
|
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
symName = strings.TrimPrefix(symName, "_")
|
|
||||||
}
|
|
||||||
if symInfo, ok := headerSymbols[symName]; ok {
|
|
||||||
symbolInfo := &types.SymbolInfo{
|
|
||||||
Mangle: symName,
|
|
||||||
CPP: symInfo.ProtoName,
|
|
||||||
Go: symInfo.GoName,
|
|
||||||
}
|
|
||||||
commonSymbols = append(commonSymbols, symbolInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commonSymbols
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadExistingSymbolTable(fileName string) (map[string]types.SymbolInfo, bool) {
|
|
||||||
if _, err := os.Stat(fileName); err != nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := os.ReadFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedJSON := cjson.ParseBytes(data)
|
|
||||||
if parsedJSON == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
existingSymbols := make(map[string]types.SymbolInfo)
|
|
||||||
arraySize := parsedJSON.GetArraySize()
|
|
||||||
|
|
||||||
for i := 0; i < int(arraySize); i++ {
|
|
||||||
item := parsedJSON.GetArrayItem(c.Int(i))
|
|
||||||
symbol := types.SymbolInfo{
|
|
||||||
Mangle: config.GetStringItem(item, "mangle", ""),
|
|
||||||
CPP: config.GetStringItem(item, "c++", ""),
|
|
||||||
Go: config.GetStringItem(item, "go", ""),
|
|
||||||
}
|
|
||||||
existingSymbols[symbol.Mangle] = symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
return existingSymbols, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenSymbolTableData(commonSymbols []*types.SymbolInfo, existingSymbols map[string]types.SymbolInfo) ([]byte, error) {
|
|
||||||
if len(existingSymbols) > 0 {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("GenSymbolTableData:generate symbol table with exist symbol table")
|
|
||||||
}
|
|
||||||
for i := range commonSymbols {
|
|
||||||
if existingSymbol, exists := existingSymbols[commonSymbols[i].Mangle]; exists && commonSymbols[i].Go != existingSymbol.Go {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("symbol", commonSymbols[i].Mangle, "already exist, use exist symbol", existingSymbol.Go)
|
|
||||||
}
|
|
||||||
commonSymbols[i].Go = existingSymbol.Go
|
|
||||||
} else {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("new symbol", commonSymbols[i].Mangle, "-", commonSymbols[i].CPP, "-", commonSymbols[i].Go)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("GenSymbolTableData:generate symbol table without symbol table")
|
|
||||||
for _, symbol := range commonSymbols {
|
|
||||||
fmt.Println("new symbol", symbol.Mangle, "-", symbol.CPP, "-", symbol.Go)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
root := cjson.Array()
|
|
||||||
defer root.Delete()
|
|
||||||
|
|
||||||
for _, symbol := range commonSymbols {
|
|
||||||
item := cjson.Object()
|
|
||||||
item.SetItem(c.Str("mangle"), cjson.String(c.AllocaCStr(symbol.Mangle)))
|
|
||||||
item.SetItem(c.Str("c++"), cjson.String(c.AllocaCStr(symbol.CPP)))
|
|
||||||
item.SetItem(c.Str("go"), cjson.String(c.AllocaCStr(symbol.Go)))
|
|
||||||
root.AddItem(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
cStr := root.Print()
|
|
||||||
if cStr == nil {
|
|
||||||
return nil, errors.New("symbol table is empty")
|
|
||||||
}
|
|
||||||
defer c.Free(unsafe.Pointer(cStr))
|
|
||||||
result := []byte(c.GoString(cStr))
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateAndUpdateSymbolTable(symbols []*nm.Symbol, headerInfos map[string]*parse.SymbolInfo, symbFile string) ([]byte, error) {
|
|
||||||
commonSymbols := GetCommonSymbols(symbols, headerInfos)
|
|
||||||
if debugSymbol {
|
|
||||||
fmt.Println("GenerateAndUpdateSymbolTable:", len(commonSymbols), "common symbols")
|
|
||||||
}
|
|
||||||
|
|
||||||
existSymbols, exist := ReadExistingSymbolTable(symbFile)
|
|
||||||
if exist && debugSymbol {
|
|
||||||
fmt.Println("GenerateAndUpdateSymbolTable:current path have exist symbol table", symbFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
symbolData, err := GenSymbolTableData(commonSymbols, existSymbols)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return symbolData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// For mutiple os test,the nm output's symbol name is different.
|
|
||||||
func AddSymbolPrefixUnder(name string, isCpp bool) string {
|
|
||||||
prefix := ""
|
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
prefix = prefix + "_"
|
|
||||||
}
|
|
||||||
if isCpp {
|
|
||||||
prefix = prefix + "_"
|
|
||||||
}
|
|
||||||
return prefix + name
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user