Files
llgo/chore/_xtool/llcppsigfetch/parse/cvt.go

668 lines
17 KiB
Go
Raw Normal View History

package parse
import (
"errors"
"fmt"
2024-08-12 12:07:45 +08:00
"os"
2024-08-15 16:08:50 +08:00
"strings"
"unsafe"
"github.com/goplus/llgo/c"
2024-08-16 11:52:22 +08:00
"github.com/goplus/llgo/c/cjson"
"github.com/goplus/llgo/c/clang"
"github.com/goplus/llgo/chore/llcppg/ast"
"github.com/goplus/llgo/chore/llcppg/token"
)
type Converter struct {
2024-08-22 21:24:25 +08:00
Files map[string]*ast.File
curLoc ast.Location
index *clang.Index
unit *clang.TranslationUnit
scopeContext []ast.Expr //namespace & class
}
2024-08-19 18:01:46 +08:00
type Config struct {
File string
Temp bool
Args []string
}
func NewConverter(config *Config) (*Converter, error) {
index, unit, err := CreateTranslationUnit(config)
if err != nil {
return nil, err
}
return &Converter{
Files: make(map[string]*ast.File),
index: index,
unit: unit,
}, nil
}
func CreateTranslationUnit(config *Config) (*clang.Index, *clang.TranslationUnit, error) {
if config.Args == nil {
config.Args = []string{"-x", "c++", "-std=c++11"}
}
2024-08-19 18:01:46 +08:00
cArgs := make([]*c.Char, len(config.Args))
for i, arg := range config.Args {
cArgs[i] = c.AllocaCStr(arg)
}
index := clang.CreateIndex(0, 0)
var unit *clang.TranslationUnit
2024-08-19 18:01:46 +08:00
if config.Temp {
content := c.AllocaCStr(config.File)
tempFile := &clang.UnsavedFile{
Filename: c.Str("temp.h"),
Contents: content,
Length: c.Ulong(c.Strlen(content)),
}
2024-08-19 18:01:46 +08:00
unit = index.ParseTranslationUnit(
tempFile.Filename,
2024-08-19 18:01:46 +08:00
unsafe.SliceData(cArgs), c.Int(len(cArgs)),
tempFile, 1,
clang.DetailedPreprocessingRecord,
)
2024-08-19 18:01:46 +08:00
} else {
2024-08-19 18:01:46 +08:00
cFile := c.AllocaCStr(config.File)
unit = index.ParseTranslationUnit(
2024-08-19 18:01:46 +08:00
cFile,
unsafe.SliceData(cArgs), c.Int(len(cArgs)),
nil, 0,
clang.DetailedPreprocessingRecord,
)
}
if unit == nil {
2024-08-19 18:01:46 +08:00
return nil, nil, errors.New("failed to parse translation unit")
}
2024-08-19 18:01:46 +08:00
return index, unit, nil
}
func (ct *Converter) Dispose() {
ct.index.Dispose()
ct.unit.Dispose()
}
2024-08-15 11:26:34 +08:00
func (ct *Converter) PushScope(cursor clang.Cursor) {
name := cursor.String()
defer name.Dispose()
ident := &ast.Ident{Name: c.GoString(name.CStr())}
2024-08-11 19:39:33 +08:00
2024-08-22 21:24:25 +08:00
if len(ct.scopeContext) == 0 {
ct.scopeContext = append(ct.scopeContext, ident)
2024-08-15 11:26:34 +08:00
} else {
2024-08-22 21:24:25 +08:00
parent := ct.scopeContext[len(ct.scopeContext)-1]
2024-08-15 11:26:34 +08:00
newContext := &ast.ScopingExpr{Parent: parent, X: ident}
2024-08-22 21:24:25 +08:00
ct.scopeContext = append(ct.scopeContext, newContext)
}
}
2024-08-15 11:26:34 +08:00
func (ct *Converter) PopScope() {
2024-08-22 21:24:25 +08:00
if len(ct.scopeContext) > 0 {
ct.scopeContext = ct.scopeContext[:len(ct.scopeContext)-1]
2024-08-15 11:26:34 +08:00
}
}
func (ct *Converter) GetCurScope() ast.Expr {
2024-08-22 21:24:25 +08:00
if len(ct.scopeContext) == 0 {
2024-08-15 11:26:34 +08:00
return nil
}
2024-08-22 21:24:25 +08:00
return ct.scopeContext[len(ct.scopeContext)-1]
2024-08-11 19:39:33 +08:00
}
func (ct *Converter) UpdateLoc(cursor clang.Cursor) {
2024-08-11 19:39:33 +08:00
loc := cursor.Location()
var file clang.File
loc.SpellingLocation(&file, nil, nil, nil)
filename := file.FileName()
defer filename.Dispose()
if filename.CStr() == nil {
//todo(zzy): For some built-in macros, there is no file.
ct.curLoc = ast.Location{File: ""}
2024-08-11 19:39:33 +08:00
return
}
filePath := c.GoString(filename.CStr())
2024-08-15 11:26:34 +08:00
ct.curLoc = ast.Location{File: filePath}
}
func (ct *Converter) GetCurFile() *ast.File {
if ct.curLoc.File == "" {
return nil
}
file, ok := ct.Files[ct.curLoc.File]
if !ok {
file = &ast.File{
Decls: make([]ast.Decl, 0),
Includes: make([]*ast.Include, 0),
Macros: make([]*ast.Macro, 0),
2024-08-11 19:39:33 +08:00
}
ct.Files[ct.curLoc.File] = file
2024-08-09 19:13:20 +08:00
}
return file
2024-08-11 19:39:33 +08:00
}
2024-08-15 11:26:34 +08:00
func (ct *Converter) CreateDeclBase(cursor clang.Cursor) ast.DeclBase {
2024-08-15 16:08:50 +08:00
rawComment := cursor.RawCommentText()
defer rawComment.Dispose()
commentGroup := &ast.CommentGroup{}
if rawComment.CStr() != nil {
commentGroup = ct.ParseComment(c.GoString(rawComment.CStr()))
}
2024-08-16 11:52:22 +08:00
loc := ct.curLoc
2024-08-15 11:26:34 +08:00
return ast.DeclBase{
2024-08-16 11:52:22 +08:00
Loc: &loc,
2024-08-15 11:26:34 +08:00
Parent: ct.GetCurScope(),
2024-08-15 16:08:50 +08:00
Doc: commentGroup,
}
}
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})
2024-08-15 11:26:34 +08:00
}
2024-08-15 16:08:50 +08:00
return commentGroup
2024-08-15 11:26:34 +08:00
}
2024-08-22 21:24:25 +08:00
// visit top decls (struct,class,function,enum & macro,include)
func visitTop(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
2024-08-15 11:26:34 +08:00
ct := (*Converter)(clientData)
ct.UpdateLoc(cursor)
curFile := ct.GetCurFile()
if curFile == nil {
return clang.ChildVisit_Continue
}
2024-08-15 11:26:34 +08:00
switch cursor.Kind {
case clang.CursorInclusionDirective:
include := ct.ProcessInclude(cursor)
curFile.Includes = append(curFile.Includes, include)
2024-08-15 11:26:34 +08:00
case clang.CursorMacroDefinition:
2024-08-22 21:24:25 +08:00
macro := ct.ProcessMacro(cursor)
curFile.Macros = append(curFile.Macros, macro)
2024-08-15 11:26:34 +08:00
case clang.CursorEnumDecl:
2024-08-22 18:49:00 +08:00
enum := ct.ProcessEnumDecl(cursor)
curFile.Decls = append(curFile.Decls, enum)
2024-08-15 11:26:34 +08:00
case clang.CursorClassDecl:
2024-08-22 18:49:00 +08:00
classDecl := ct.ProcessClassDecl(cursor)
curFile.Decls = append(curFile.Decls, classDecl)
2024-08-15 11:26:34 +08:00
case clang.CursorStructDecl:
2024-08-22 18:49:00 +08:00
structDecl := ct.ProcessStructDecl(cursor)
curFile.Decls = append(curFile.Decls, structDecl)
2024-08-20 10:43:01 +08:00
case clang.CursorUnionDecl:
2024-08-22 18:49:00 +08:00
unionDecl := ct.ProcessUnionDecl(cursor)
curFile.Decls = append(curFile.Decls, unionDecl)
2024-08-15 11:26:34 +08:00
case clang.CursorFunctionDecl:
2024-08-22 18:49:00 +08:00
curFile.Decls = append(curFile.Decls, ct.ProcessFuncDecl(cursor))
case clang.CursorTypedefDecl:
2024-08-22 18:49:00 +08:00
curFile.Decls = append(curFile.Decls, ct.ProcessTypeDefDecl(cursor))
2024-08-15 11:26:34 +08:00
case clang.CursorNamespace:
ct.PushScope(cursor)
2024-08-22 21:24:25 +08:00
clang.VisitChildren(cursor, visitTop, c.Pointer(ct))
2024-08-15 11:26:34 +08:00
ct.PopScope()
}
return clang.ChildVisit_Continue
}
func (ct *Converter) Convert() (map[string]*ast.File, error) {
cursor := ct.unit.Cursor()
2024-08-22 21:24:25 +08:00
// visit top decls (struct,class,function & macro,include)
clang.VisitChildren(cursor, visitTop, c.Pointer(ct))
2024-08-16 11:52:22 +08:00
return ct.Files, nil
2024-08-15 11:26:34 +08:00
}
2024-08-11 19:39:33 +08:00
func (ct *Converter) ProcessType(t clang.Type) ast.Expr {
2024-08-22 15:57:21 +08:00
2024-08-12 12:07:45 +08:00
if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin {
return ct.ProcessBuiltinType(t)
}
2024-08-22 15:57:21 +08:00
if t.Kind == clang.TypeElaborated {
return ct.ProcessElaboratedType(t)
}
var expr ast.Expr
2024-08-09 19:13:20 +08:00
switch t.Kind {
case clang.TypePointer:
expr = &ast.PointerType{X: ct.ProcessType(t.PointeeType())}
2024-08-22 12:15:06 +08:00
case clang.TypeLValueReference, clang.TypeRValueReference:
expr = &ast.LvalueRefType{X: ct.ProcessType(t.NonReferenceType())}
2024-08-09 19:13:20 +08:00
case clang.TypeFunctionProto:
2024-08-22 18:49:00 +08:00
// function type will only collect return type, params will be collected in ProcessFuncDecl
2024-08-09 19:13:20 +08:00
ret := ct.ProcessType(t.ResultType())
2024-08-13 18:35:33 +08:00
expr = &ast.FuncType{Ret: ret}
case clang.TypeConstantArray, clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray:
if t.Kind == clang.TypeConstantArray {
2024-08-19 12:07:30 +08:00
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()),
2024-08-19 12:07:30 +08:00
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()),
}
2024-08-09 19:13:20 +08:00
}
}
return expr
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessTypeDefDecl(cursor clang.Cursor) *ast.TypedefDecl {
name := cursor.String()
defer name.Dispose()
return &ast.TypedefDecl{
DeclBase: ct.CreateDeclBase(cursor),
Name: &ast.Ident{Name: c.GoString(name.CStr())},
2024-08-22 15:57:21 +08:00
Type: ct.ProcessType(cursor.TypedefDeclUnderlyingType()),
}
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessFuncDecl(cursor clang.Cursor) *ast.FuncDecl {
2024-08-09 19:13:20 +08:00
name := cursor.String()
defer name.Dispose()
2024-08-13 18:35:33 +08:00
// function type will only collect return type
// ProcessType can't get the field names,will collect in follows
2024-08-09 19:13:20 +08:00
funcType, ok := ct.ProcessType(cursor.Type()).(*ast.FuncType)
if !ok {
fmt.Println("failed to process function type")
return nil
2024-08-09 19:13:20 +08:00
}
params := ct.ProcessFieldList(cursor)
2024-08-13 18:35:33 +08:00
funcType.Params = params
2024-08-09 19:13:20 +08:00
fn := &ast.FuncDecl{
2024-08-15 11:26:34 +08:00
DeclBase: ct.CreateDeclBase(cursor),
Name: &ast.Ident{Name: c.GoString(name.CStr())},
Type: funcType,
2024-08-09 19:13:20 +08:00
}
2024-08-26 10:56:36 +08:00
if cursor.IsFunctionInlined() != 0 {
fn.IsInline = true
}
2024-08-26 10:56:36 +08:00
if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorDestructor || cursor.Kind == clang.CursorConstructor {
if cursor.Kind == clang.CursorDestructor {
fn.IsDestructor = true
}
if cursor.Kind == clang.CursorConstructor {
fn.IsConstructor = true
if cursor.IsExplicit() != 0 {
fn.IsExplicit = true
}
}
if cursor.IsStatic() != 0 {
fn.IsStatic = true
}
// virtual & pure virtual
if cursor.IsVirtual() != 0 || cursor.IsPureVirtual() != 0 {
fn.IsVirtual = true
}
if cursor.IsConst() != 0 {
fn.IsConst = true
}
2024-08-26 10:56:36 +08:00
var numOverridden c.Uint
var overridden *clang.Cursor
cursor.OverriddenCursors(&overridden, &numOverridden)
if numOverridden > 0 {
fn.IsOverride = true
}
overridden.DisposeOverriddenCursors()
} else {
if cursor.StorageClass() == clang.SCStatic {
fn.IsStatic = true
}
}
return fn
}
2024-08-19 12:07:30 +08:00
type visitEnumContext struct {
enum *[]*ast.EnumItem
converter *Converter
}
func visitEnum(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
ctx := (*visitEnumContext)(clientData)
if cursor.Kind == clang.CursorEnumConstantDecl {
name := cursor.String()
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))
defer name.Dispose()
enum := &ast.EnumItem{
Name: &ast.Ident{Name: c.GoString(name.CStr())},
Value: &ast.BasicLit{
Kind: ast.IntLit,
Value: c.GoString(val),
},
}
*ctx.enum = append(*ctx.enum, enum)
}
return clang.ChildVisit_Continue
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessEnumDecl(cursor clang.Cursor) *ast.EnumTypeDecl {
2024-08-19 12:07:30 +08:00
name := cursor.String()
defer name.Dispose()
items := make([]*ast.EnumItem, 0)
ctx := &visitEnumContext{
enum: &items,
converter: ct,
}
clang.VisitChildren(cursor, visitEnum, c.Pointer(ctx))
return &ast.EnumTypeDecl{
2024-08-19 12:07:30 +08:00
DeclBase: ct.CreateDeclBase(cursor),
Name: &ast.Ident{Name: c.GoString(name.CStr())},
2024-08-23 14:57:36 +08:00
Type: &ast.EnumType{
Items: items,
},
2024-08-19 12:07:30 +08:00
}
}
2024-08-22 21:24:25 +08:00
// current only collect macro which defined in file
func (ct *Converter) ProcessMacro(cursor clang.Cursor) *ast.Macro {
2024-08-16 18:39:09 +08:00
name := cursor.String()
defer name.Dispose()
ran := cursor.Extent()
var numTokens c.Uint
var tokens *clang.Token
ct.unit.Tokenize(ran, &tokens, &numTokens)
2024-08-20 11:01:08 +08:00
defer ct.unit.DisposeTokens(tokens, numTokens)
2024-08-16 18:39:09 +08:00
tokensSlice := unsafe.Slice(tokens, int(numTokens))
macro := &ast.Macro{
Name: c.GoString(name.CStr()),
Tokens: make([]*ast.Token, 0),
}
for _, tok := range tokensSlice {
tokStr := ct.unit.Token(tok)
macro.Tokens = append(macro.Tokens, &ast.Token{
Token: toToken(tok),
Lit: c.GoString(tokStr.CStr()),
})
tokStr.Dispose()
2024-08-16 18:39:09 +08:00
}
return macro
2024-08-16 18:39:09 +08:00
}
func (ct *Converter) ProcessInclude(cursor clang.Cursor) *ast.Include {
2024-08-18 11:16:43 +08:00
name := cursor.String()
defer name.Dispose()
return &ast.Include{Path: c.GoString(name.CStr())}
2024-08-18 11:16:43 +08:00
}
type visitFieldContext struct {
2024-08-13 18:35:33 +08:00
params *ast.FieldList
converter *Converter
}
func visitFieldList(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
ctx := (*visitFieldContext)(clientData)
if cursor.Kind == clang.CursorParmDecl || cursor.Kind == clang.CursorFieldDecl {
2024-08-13 18:35:33 +08:00
paramName := cursor.String()
defer paramName.Dispose()
argType := ctx.converter.ProcessType(cursor.Type())
// 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;
// };
2024-08-13 18:35:33 +08:00
ctx.params.List = append(ctx.params.List,
&ast.Field{
//todo(zzy): comment & doc
Doc: &ast.CommentGroup{},
Comment: &ast.CommentGroup{},
Type: argType,
2024-08-13 18:35:33 +08:00
Names: []*ast.Ident{
{Name: c.GoString(paramName.CStr())},
},
})
}
return clang.ChildVisit_Continue
}
func (ct *Converter) ProcessFieldList(cursor clang.Cursor) *ast.FieldList {
2024-08-13 18:35:33 +08:00
params := &ast.FieldList{List: []*ast.Field{}}
ctx := &visitFieldContext{
2024-08-13 18:35:33 +08:00
params: params,
converter: ct,
}
clang.VisitChildren(cursor, visitFieldList, c.Pointer(ctx))
2024-08-13 18:35:33 +08:00
return params
}
type visitMethodsContext struct {
methods *[]*ast.FuncDecl
converter *Converter
}
func visitMethods(cursor, parent clang.Cursor, clientData unsafe.Pointer) clang.ChildVisitResult {
ctx := (*visitMethodsContext)(clientData)
if cursor.Kind == clang.CursorCXXMethod || cursor.Kind == clang.CursorConstructor || cursor.Kind == clang.CursorDestructor {
2024-08-22 18:49:00 +08:00
method := ctx.converter.ProcessFuncDecl(cursor)
if method != nil {
*ctx.methods = append(*ctx.methods, method)
}
}
return clang.ChildVisit_Continue
}
func (ct *Converter) ProcessMethods(cursor clang.Cursor) []*ast.FuncDecl {
methods := make([]*ast.FuncDecl, 0)
ctx := &visitMethodsContext{
methods: &methods,
converter: ct,
}
clang.VisitChildren(cursor, visitMethods, c.Pointer(ctx))
return methods
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessRecordDecl(cursor clang.Cursor, tag ast.Tag) *ast.TypeDecl {
2024-08-21 14:50:42 +08:00
anony := cursor.IsAnonymousRecordDecl()
var name *ast.Ident
if anony == 0 {
cursorName := cursor.String()
defer cursorName.Dispose()
name = &ast.Ident{Name: c.GoString(cursorName.CStr())}
}
2024-08-22 18:49:00 +08:00
return &ast.TypeDecl{
DeclBase: ct.CreateDeclBase(cursor),
2024-08-21 14:50:42 +08:00
Name: name,
2024-08-22 18:49:00 +08:00
Type: ct.ProcessRecordType(cursor, tag),
}
2024-08-22 18:49:00 +08:00
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessStructDecl(cursor clang.Cursor) *ast.TypeDecl {
return ct.ProcessRecordDecl(cursor, ast.Struct)
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessUnionDecl(cursor clang.Cursor) *ast.TypeDecl {
return ct.ProcessRecordDecl(cursor, ast.Union)
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessClassDecl(cursor clang.Cursor) *ast.TypeDecl {
// Pushing class scope before processing its type and popping after
base := ct.CreateDeclBase(cursor)
ct.PushScope(cursor)
typ := ct.ProcessRecordType(cursor, ast.Class)
ct.PopScope()
return &ast.TypeDecl{
DeclBase: base,
Name: &ast.Ident{Name: c.GoString(cursor.String().CStr())},
Type: typ,
}
2024-08-20 10:43:01 +08:00
}
2024-08-22 18:49:00 +08:00
func (ct *Converter) ProcessRecordType(cursor clang.Cursor, tag ast.Tag) *ast.RecordType {
return &ast.RecordType{
Tag: tag,
Fields: ct.ProcessFieldList(cursor),
Methods: ct.ProcessMethods(cursor),
}
}
2024-08-12 12:07:45 +08:00
2024-08-22 15:57:21 +08:00
func (ct *Converter) ProcessElaboratedType(t clang.Type) ast.Expr {
name := t.String()
defer name.Dispose()
typeName := c.GoString(name.CStr())
tagMap := map[string]ast.Tag{
"struct": ast.Struct,
"union": ast.Union,
"enum": ast.Enum,
"class": ast.Class,
}
// 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,
2024-08-23 15:13:15 +08:00
Name: qualifiedExpr(parts[1]),
2024-08-22 15:57:21 +08:00
}
}
}
2024-08-23 15:13:15 +08:00
return qualifiedExpr(typeName)
2024-08-22 15:57:21 +08:00
}
2024-08-12 12:07:45 +08:00
func (ct *Converter) ProcessBuiltinType(t clang.Type) *ast.BuiltinType {
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
2024-08-19 21:39:42 +08:00
case clang.TypeComplex:
2024-08-19 18:01:46 +08:00
kind = ast.Complex
complexKind := t.ElementType().Kind
2024-08-19 21:39:42 +08:00
if complexKind == clang.TypeLongDouble {
flags |= ast.Long | ast.Double
} else if complexKind == clang.TypeDouble {
flags |= ast.Double
}
// float complfex flag is not set
2024-08-12 12:07:45 +08:00
default:
// like IBM128,NullPtr,Accum
2024-08-15 09:27:41 +08:00
kindStr := t.Kind.String()
defer kindStr.Dispose()
fmt.Fprintln(os.Stderr, "todo: unknown builtin type:", c.GoString(kindStr.CStr()))
2024-08-12 12:07:45 +08:00
}
if IsExplicitSigned(t) {
flags |= ast.Signed
} else if IsExplicitUnsigned(t) {
flags |= ast.Unsigned
}
return &ast.BuiltinType{
Kind: kind,
Flags: flags,
}
}
2024-08-16 11:52:22 +08:00
func (ct *Converter) MarshalASTFiles() *cjson.JSON {
return MarshalASTFiles(ct.Files)
}
2024-08-12 12:07:45 +08:00
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 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)
}
}
2024-08-23 15:13:15 +08:00
func qualifiedExpr(name string) ast.Expr {
parts := strings.Split(name, "::")
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
}