222 lines
5.3 KiB
Go
222 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"github.com/goplus/llgo/c"
|
|
"github.com/goplus/llgo/c/clang"
|
|
)
|
|
|
|
type Data struct {
|
|
Depth c.Uint
|
|
Unit *clang.TranslationUnit
|
|
}
|
|
|
|
var accessMap = map[clang.CXXAccessSpecifier]string{
|
|
clang.CXXInvalidAccessSpecifier: "invalid",
|
|
clang.CXXPublic: "public",
|
|
clang.CXXProtected: "protected",
|
|
clang.CXXPrivate: "private",
|
|
}
|
|
|
|
func printIndent(depth c.Uint) {
|
|
fmt.Print(strings.Repeat(" ", int(depth)))
|
|
}
|
|
|
|
func accessToString(spec clang.CXXAccessSpecifier) string {
|
|
if str, ok := accessMap[spec]; ok {
|
|
return str
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func visit(cursor, parent clang.Cursor, ClientData c.Pointer) clang.ChildVisitResult {
|
|
data := (*Data)(ClientData)
|
|
printAST(cursor, data)
|
|
return clang.ChildVisit_Continue
|
|
}
|
|
|
|
func printType(t clang.Type, data *Data) {
|
|
printIndent(data.Depth)
|
|
|
|
typeSpell := t.String()
|
|
typeKind := t.Kind.String()
|
|
|
|
if t.Kind == clang.TypeInvalid {
|
|
} else if t.Kind == clang.TypeUnexposed {
|
|
c.Printf(c.Str("<UnexposedType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
|
|
} else if t.Kind >= clang.TypeFirstBuiltin && t.Kind <= clang.TypeLastBuiltin {
|
|
c.Printf(c.Str("<BuiltinType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
|
|
} else if t.Kind > clang.TypeComplex {
|
|
c.Printf(c.Str("<ComplexType|%s>: %s\n"), typeKind.CStr(), typeSpell.CStr())
|
|
}
|
|
|
|
data.Depth++
|
|
switch t.Kind {
|
|
case clang.TypePointer:
|
|
printType(t.PointeeType(), data)
|
|
case clang.TypeIncompleteArray, clang.TypeVariableArray, clang.TypeDependentSizedArray, clang.TypeConstantArray:
|
|
printType(t.ArrayElementType(), data)
|
|
case clang.TypeTypedef:
|
|
printType(t.TypeDeclaration().TypedefDeclUnderlyingType(), data)
|
|
case clang.TypeElaborated:
|
|
printType(t.NamedType(), data)
|
|
case clang.TypeFunctionProto:
|
|
printType(t.ResultType(), data)
|
|
for i := 0; i < int(t.NumArgTypes()); i++ {
|
|
printType(t.ArgType(c.Uint(i)), data)
|
|
}
|
|
}
|
|
data.Depth--
|
|
|
|
typeKind.Dispose()
|
|
typeSpell.Dispose()
|
|
}
|
|
|
|
func printLocation(cursor clang.Cursor) {
|
|
loc := cursor.Location()
|
|
var file clang.File
|
|
var line, column c.Uint
|
|
|
|
loc.SpellingLocation(&file, &line, &column, nil)
|
|
filename := file.FileName()
|
|
defer filename.Dispose()
|
|
|
|
c.Printf(c.Str("(Loc:%s:%d:%d)\n"), filename.CStr(), line, column)
|
|
}
|
|
|
|
func printAccess(cursor clang.Cursor) {
|
|
kind := cursor.Kind.String()
|
|
spell := cursor.String()
|
|
defer kind.Dispose()
|
|
defer spell.Dispose()
|
|
|
|
c.Printf(c.Str("%s: %s %s"), kind.CStr(), spell.CStr(), c.AllocaCStr(accessToString(cursor.CXXAccessSpecifier())))
|
|
printLocation(cursor)
|
|
}
|
|
|
|
func printMacro(cursor clang.Cursor, unit *clang.TranslationUnit) {
|
|
kind := cursor.Kind.String()
|
|
defer kind.Dispose()
|
|
|
|
c.Printf(c.Str("%s: "), kind.CStr())
|
|
ran := cursor.Extent()
|
|
var numTokens c.Uint
|
|
var tokens *clang.Token
|
|
unit.Tokenize(ran, &tokens, &numTokens)
|
|
defer unit.DisposeTokens(tokens, numTokens)
|
|
|
|
tokensSlice := unsafe.Slice(tokens, int(numTokens))
|
|
for _, tok := range tokensSlice {
|
|
tokStr := unit.Token(tok)
|
|
c.Printf(c.Str("%s "), tokStr.CStr())
|
|
tokStr.Dispose()
|
|
}
|
|
printLocation(cursor)
|
|
}
|
|
|
|
func printFunc(cursor clang.Cursor, data *Data) {
|
|
kind := cursor.Kind.String()
|
|
spell := cursor.String()
|
|
symbol := cursor.Mangling()
|
|
defer symbol.Dispose()
|
|
defer kind.Dispose()
|
|
defer spell.Dispose()
|
|
|
|
c.Printf(c.Str("%s: %s (Symbol: %s)"), kind.CStr(), spell.CStr(), symbol.CStr())
|
|
printLocation(cursor)
|
|
printType(cursor.Type(), data)
|
|
}
|
|
|
|
func printEnumConstant(cursor clang.Cursor) {
|
|
kind := cursor.Kind.String()
|
|
spell := cursor.String()
|
|
defer kind.Dispose()
|
|
defer spell.Dispose()
|
|
|
|
c.Printf(c.Str("%s: %s:%lld"), kind.CStr(), spell.CStr(), cursor.EnumConstantDeclValue())
|
|
printLocation(cursor)
|
|
}
|
|
|
|
func printDefault(cursor clang.Cursor, data *Data) {
|
|
kind := cursor.Kind.String()
|
|
spell := cursor.String()
|
|
defer kind.Dispose()
|
|
defer spell.Dispose()
|
|
|
|
// node which has type
|
|
if cursor.Type().Kind != clang.TypeInvalid {
|
|
c.Printf(c.Str("%s: %s"), kind.CStr(), spell.CStr())
|
|
printLocation(cursor)
|
|
printType(cursor.Type(), data)
|
|
} else {
|
|
c.Printf(c.Str("%s: %s\n"), kind.CStr(), spell.CStr())
|
|
}
|
|
}
|
|
|
|
func printAST(cursor clang.Cursor, data *Data) {
|
|
kind := cursor.Kind.String()
|
|
spell := cursor.String()
|
|
|
|
printIndent(data.Depth)
|
|
|
|
switch cursor.Kind {
|
|
case clang.CursorCXXAccessSpecifier:
|
|
printAccess(cursor)
|
|
case clang.CursorMacroDefinition:
|
|
printMacro(cursor, data.Unit)
|
|
case clang.CursorFunctionDecl, clang.CursorCXXMethod, clang.CursorConstructor, clang.CursorDestructor:
|
|
printFunc(cursor, data)
|
|
case clang.CursorEnumConstantDecl:
|
|
printEnumConstant(cursor)
|
|
default:
|
|
printDefault(cursor, data)
|
|
}
|
|
|
|
data.Depth++
|
|
clang.VisitChildren(cursor, visit, c.Pointer(data))
|
|
data.Depth--
|
|
|
|
kind.Dispose()
|
|
spell.Dispose()
|
|
}
|
|
|
|
func main() {
|
|
if c.Argc != 2 {
|
|
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
|
|
return
|
|
}
|
|
|
|
args := make([]*c.Char, 3)
|
|
args[0] = c.Str("-x")
|
|
args[1] = c.Str("c++")
|
|
args[2] = c.Str("-std=c++11")
|
|
|
|
sourceFile := *c.Advance(c.Argv, 1)
|
|
index := clang.CreateIndex(0, 0)
|
|
unit := index.ParseTranslationUnit(
|
|
sourceFile,
|
|
unsafe.SliceData(args), 3,
|
|
nil, 0,
|
|
clang.DetailedPreprocessingRecord,
|
|
)
|
|
defer index.Dispose()
|
|
defer unit.Dispose()
|
|
|
|
if unit == nil {
|
|
println("Unable to parse translation unit. Quitting.")
|
|
c.Exit(1)
|
|
}
|
|
|
|
cursor := unit.Cursor()
|
|
|
|
Data := &Data{
|
|
Depth: 0,
|
|
Unit: unit,
|
|
}
|
|
printAST(cursor, Data)
|
|
}
|