Merge pull request #888 from xushiwei/q
mv llcppg => github.com/goplus/llcppg
This commit is contained in:
3
.github/workflows/go.yml
vendored
3
.github/workflows/go.yml
vendored
@@ -101,9 +101,6 @@ jobs:
|
||||
- name: Install
|
||||
run: go install ./...
|
||||
|
||||
- name: Install llcppg
|
||||
run: bash .github/workflows/install_llcppg_depend.sh
|
||||
|
||||
- name: Test
|
||||
if: ${{!startsWith(matrix.os, 'macos')}}
|
||||
run: go test -v ./...
|
||||
|
||||
6
.github/workflows/install_llcppg_depend.sh
vendored
6
.github/workflows/install_llcppg_depend.sh
vendored
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
llgo install ./chore/_xtool/llcppsymg
|
||||
llgo install ./chore/_xtool/llcppsigfetch
|
||||
go install ./chore/gogensig
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,21 +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
|
||||
|
||||
func main() {
|
||||
// TODO(xsw): implement gogensig tool
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
llcppg - Autogen tool for C/C++ libraries
|
||||
====
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
llcppg [config-file]
|
||||
```
|
||||
|
||||
If `config-file` is not specified, a `llcppg.cfg` file is used in current directory. The configuration file format is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inireader",
|
||||
"cflags": "$(pkg-config --cflags inireader)",
|
||||
"include": [
|
||||
"INIReader.h",
|
||||
"AnotherHeaderFile.h"
|
||||
],
|
||||
"libs": "$(pkg-config --libs inireader)",
|
||||
"trimPrefixes": ["Ini", "INI"]
|
||||
}
|
||||
```
|
||||
|
||||
## Design
|
||||
|
||||
See [llcppg Design](design.md).
|
||||
@@ -1,379 +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 ast
|
||||
|
||||
import "github.com/goplus/llgo/chore/llcppg/token"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
type Node interface {
|
||||
}
|
||||
|
||||
type Expr interface {
|
||||
Node
|
||||
exprNode()
|
||||
}
|
||||
|
||||
type Decl interface {
|
||||
Node
|
||||
declNode()
|
||||
}
|
||||
|
||||
type Stmt interface {
|
||||
Node
|
||||
stmtNode()
|
||||
}
|
||||
|
||||
type PPD interface { // preprocessing directive
|
||||
Node
|
||||
ppdNode()
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
type AccessSpecifier uint
|
||||
|
||||
const (
|
||||
Invalid AccessSpecifier = iota
|
||||
Public
|
||||
Protected
|
||||
Private
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// Expressions (Types are also expressions)
|
||||
|
||||
type BasicLitKind uint
|
||||
|
||||
const (
|
||||
IntLit BasicLitKind = iota
|
||||
FloatLit
|
||||
CharLit
|
||||
StringLit
|
||||
)
|
||||
|
||||
type BasicLit struct {
|
||||
Kind BasicLitKind
|
||||
Value string
|
||||
}
|
||||
|
||||
func (*BasicLit) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type TypeKind uint
|
||||
|
||||
const (
|
||||
Void TypeKind = iota
|
||||
Bool
|
||||
Char
|
||||
Char16
|
||||
Char32
|
||||
WChar
|
||||
Int
|
||||
Int128
|
||||
Float
|
||||
Float16
|
||||
Float128
|
||||
Complex
|
||||
)
|
||||
|
||||
type TypeFlag uint
|
||||
|
||||
const (
|
||||
Signed TypeFlag = 1 << iota
|
||||
Unsigned
|
||||
Long
|
||||
LongLong
|
||||
Double
|
||||
Short
|
||||
)
|
||||
|
||||
// [signed/unsigned/short/long/long long/double] [int]/char/float/complex/bool
|
||||
type BuiltinType struct {
|
||||
Kind TypeKind
|
||||
Flags TypeFlag
|
||||
}
|
||||
|
||||
func (*BuiltinType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Name
|
||||
type Ident struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (*Ident) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Tag int
|
||||
|
||||
const (
|
||||
Struct Tag = iota
|
||||
Union
|
||||
Enum
|
||||
Class
|
||||
)
|
||||
|
||||
// struct/union/enum/class (A::B::)Name
|
||||
type TagExpr struct {
|
||||
Tag Tag
|
||||
Name Expr // ScopingExpr, Ident
|
||||
}
|
||||
|
||||
func (*TagExpr) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// type a, ...
|
||||
type Variadic struct {
|
||||
}
|
||||
|
||||
func (*Variadic) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// (X)
|
||||
type ParenExpr struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*ParenExpr) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Parent::X
|
||||
type ScopingExpr struct {
|
||||
Parent Expr
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*ScopingExpr) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// X*
|
||||
type PointerType struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*PointerType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// X&
|
||||
type LvalueRefType struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*LvalueRefType) exprNode() {}
|
||||
|
||||
// X&&
|
||||
type RvalueRefType struct {
|
||||
X Expr
|
||||
}
|
||||
|
||||
func (*RvalueRefType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Elt[Len]
|
||||
// Elt[]
|
||||
type ArrayType struct {
|
||||
Elt Expr
|
||||
Len Expr // optional
|
||||
}
|
||||
|
||||
func (*ArrayType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Comment struct {
|
||||
Text string // comment text (excluding '\n' for //-style comments)
|
||||
}
|
||||
|
||||
func (*Comment) exprNode() {}
|
||||
|
||||
type CommentGroup struct {
|
||||
List []*Comment // len(List) > 0
|
||||
}
|
||||
|
||||
func (*CommentGroup) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Field struct {
|
||||
Doc *CommentGroup // associated documentation; or nil
|
||||
Type Expr // field/method/parameter type; or nil
|
||||
Names []*Ident // field/method/(type) parameter names; or nil
|
||||
Comment *CommentGroup // line comments; or nil
|
||||
Access AccessSpecifier // field access(Record Type); Struct Field default is Public,Class Field default is Private
|
||||
IsStatic bool // static field
|
||||
}
|
||||
|
||||
func (*Field) exprNode() {}
|
||||
|
||||
type FieldList struct {
|
||||
List []*Field // field list; or nil
|
||||
}
|
||||
|
||||
func (*FieldList) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Ret (*)(Params)
|
||||
type FuncType struct {
|
||||
Params *FieldList
|
||||
Ret Expr
|
||||
}
|
||||
|
||||
func (*FuncType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type RecordType struct {
|
||||
Tag Tag
|
||||
Fields *FieldList
|
||||
Methods []*FuncDecl
|
||||
}
|
||||
|
||||
func (*RecordType) exprNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Template<Arg1, Arg2, ...>
|
||||
type InstantiationType struct {
|
||||
Template Expr
|
||||
Args *FieldList
|
||||
}
|
||||
|
||||
func (*InstantiationType) exprNode() {}
|
||||
|
||||
// =============================================================================
|
||||
// Declarations
|
||||
|
||||
type Location struct {
|
||||
File string
|
||||
}
|
||||
|
||||
type DeclBase struct {
|
||||
Doc *CommentGroup // associated documentation; or nil
|
||||
Loc *Location
|
||||
Parent Expr // namespace or class
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// typedef Type Name;
|
||||
type TypedefDecl struct {
|
||||
DeclBase
|
||||
Type Expr
|
||||
Name *Ident
|
||||
}
|
||||
|
||||
func (*TypedefDecl) declNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type EnumItem struct {
|
||||
Name *Ident
|
||||
Value Expr // optional
|
||||
}
|
||||
|
||||
func (*EnumItem) exprNode() {}
|
||||
|
||||
type EnumType struct {
|
||||
Items []*EnumItem
|
||||
}
|
||||
|
||||
func (*EnumType) exprNode() {}
|
||||
|
||||
// enum Name { Item1, Item2, ... };
|
||||
type EnumTypeDecl struct {
|
||||
DeclBase
|
||||
Name *Ident
|
||||
Type *EnumType
|
||||
}
|
||||
|
||||
func (*EnumTypeDecl) declNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// Ret Name(Params);
|
||||
type FuncDecl struct {
|
||||
DeclBase
|
||||
Name *Ident
|
||||
MangledName string // C: same as Name, C++: mangled
|
||||
Type *FuncType
|
||||
IsInline bool
|
||||
IsStatic bool
|
||||
|
||||
// Class method specific fields
|
||||
IsConst bool // const member function
|
||||
IsExplicit bool // explicit constructor
|
||||
IsConstructor bool
|
||||
IsDestructor bool
|
||||
IsVirtual bool
|
||||
IsOverride bool
|
||||
}
|
||||
|
||||
func (*FuncDecl) declNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
// struct/union/class Name { Field1, Field2, ... };
|
||||
type TypeDecl struct {
|
||||
DeclBase
|
||||
Name *Ident
|
||||
Type *RecordType
|
||||
}
|
||||
|
||||
func (*TypeDecl) declNode() {}
|
||||
|
||||
// =============================================================================
|
||||
// AST File
|
||||
|
||||
type Include struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
func (*Include) ppdNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type Token struct {
|
||||
Token token.Token
|
||||
Lit string
|
||||
}
|
||||
|
||||
type Macro struct {
|
||||
Name string
|
||||
Tokens []*Token // Tokens[0].Lit is the macro name
|
||||
}
|
||||
|
||||
func (*Macro) ppdNode() {}
|
||||
|
||||
// ------------------------------------------------
|
||||
|
||||
type File struct {
|
||||
Decls []Decl `json:"decls"`
|
||||
Includes []*Include `json:"includes,omitempty"`
|
||||
Macros []*Macro `json:"macros,omitempty"`
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -1,85 +0,0 @@
|
||||
llcppg Design
|
||||
=====
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
llcppg [config-file]
|
||||
```
|
||||
|
||||
If `config-file` is not specified, a `llcppg.cfg` file is used in current directory. The configuration file format is as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "inih",
|
||||
"cflags": "$(pkg-config --cflags inireader)",
|
||||
"include": [
|
||||
"INIReader.h",
|
||||
"AnotherHeaderFile.h"
|
||||
],
|
||||
"libs": "$(pkg-config --libs inireader)",
|
||||
"trimPrefixes": ["Ini", "INI"],
|
||||
"cplusplus":true
|
||||
}
|
||||
```
|
||||
|
||||
## Steps
|
||||
|
||||
1. llcppsymg: Generate symbol table for a C/C++ library
|
||||
2. Manually modify the desired Go symbols in symbol table
|
||||
3. llcppsigfetch: Fetch information of C/C++ symbols
|
||||
4. gogensig: Generate a go package by information of symbols
|
||||
|
||||
|
||||
### llcppsymg
|
||||
|
||||
```sh
|
||||
llcppsymg config-file
|
||||
llcppsymg - # read config from stdin
|
||||
```
|
||||
|
||||
It generates a symbol table file named `llcppg.symb.json`. Its file format is as follows:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"mangle": "_ZN9INIReaderC1EPKcm",
|
||||
"c++": "INIReader::INIReader(char const*, unsigned long)",
|
||||
"go": "(*Reader).Init__0"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
### llcppsigfetch
|
||||
|
||||
```sh
|
||||
llcppsigfetch config-file
|
||||
llcppsigfetch - # read config from stdin
|
||||
```
|
||||
|
||||
It fetches information of C/C++ symbols and print to stdout. Its format is as follows:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"path": "/path/to/file.h",
|
||||
"doc": {
|
||||
"decls": [],
|
||||
"macros": [],
|
||||
"includes": [
|
||||
{
|
||||
"path": "incfile.h"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### gogensig
|
||||
|
||||
```sh
|
||||
gogensig ast-file
|
||||
gogensig - # read AST from stdin
|
||||
```
|
||||
@@ -1,93 +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 (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/goplus/llgo/chore/llcppg/types"
|
||||
"github.com/goplus/llgo/xtool/env"
|
||||
)
|
||||
|
||||
func llcppsymg(conf []byte) error {
|
||||
cmd := exec.Command("llcppsymg", "-")
|
||||
cmd.Stdin = bytes.NewReader(conf)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func llcppsigfetch(conf []byte, out *io.PipeWriter) {
|
||||
cmd := exec.Command("llcppsigfetch", "-")
|
||||
cmd.Stdin = bytes.NewReader(conf)
|
||||
cmd.Stdout = out
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
check(err)
|
||||
out.Close()
|
||||
}
|
||||
|
||||
func gogensig(in io.Reader) error {
|
||||
cmd := exec.Command("gogensig", "-")
|
||||
cmd.Stdin = in
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfgFile := "llcppg.cfg"
|
||||
if len(os.Args) > 1 {
|
||||
cfgFile = os.Args[1]
|
||||
}
|
||||
if cfgFile == "-h" || cfgFile == "--help" {
|
||||
fmt.Fprintln(os.Stderr, "Usage: llcppg [config-file]")
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open(cfgFile)
|
||||
check(err)
|
||||
defer f.Close()
|
||||
|
||||
var conf types.Config
|
||||
json.NewDecoder(f).Decode(&conf)
|
||||
conf.CFlags = env.ExpandEnv(conf.CFlags)
|
||||
conf.Libs = env.ExpandEnv(conf.Libs)
|
||||
|
||||
b, err := json.MarshalIndent(&conf, "", " ")
|
||||
check(err)
|
||||
|
||||
err = llcppsymg(b)
|
||||
check(err)
|
||||
|
||||
r, w := io.Pipe()
|
||||
go llcppsigfetch(b, w)
|
||||
|
||||
err = gogensig(r)
|
||||
check(err)
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package token
|
||||
|
||||
type Token uint
|
||||
|
||||
const (
|
||||
ILLEGAL Token = iota
|
||||
|
||||
/**
|
||||
* A token that contains some kind of punctuation.
|
||||
*/
|
||||
PUNCT
|
||||
|
||||
/**
|
||||
* A language keyword.
|
||||
*/
|
||||
KEYWORD
|
||||
|
||||
/**
|
||||
* An identifier (that is not a keyword).
|
||||
*/
|
||||
IDENT
|
||||
|
||||
/**
|
||||
* A numeric, string, or character literal.
|
||||
*/
|
||||
LITERAL
|
||||
|
||||
/**
|
||||
* A comment.
|
||||
*/
|
||||
COMMENT
|
||||
)
|
||||
@@ -1,33 +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 types
|
||||
|
||||
// Config represents a configuration for the llcppg tool.
|
||||
type Config struct {
|
||||
Name string `json:"name"`
|
||||
CFlags string `json:"cflags"`
|
||||
Libs string `json:"libs"`
|
||||
Include []string `json:"include"`
|
||||
TrimPrefixes []string `json:"trimPrefixes"`
|
||||
Cplusplus bool `json:"cplusplus"`
|
||||
}
|
||||
|
||||
type SymbolInfo struct {
|
||||
Mangle string `json:"mangle"` // C++ Symbol
|
||||
CPP string `json:"c++"` // C++ function name
|
||||
Go string `json:"go"` // Go function name
|
||||
}
|
||||
Reference in New Issue
Block a user