From 45bd80ff017bbe7c28e1c048112f5bc7f49588de Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Thu, 22 May 2025 14:23:14 +0800 Subject: [PATCH 1/3] feat: add flag `-repo-id` for specify repoid --- lang/parse.go | 7 +++++++ main.go | 55 +++++++++++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/lang/parse.go b/lang/parse.go index 95f3d77..729ccb1 100644 --- a/lang/parse.go +++ b/lang/parse.go @@ -40,6 +40,8 @@ type ParseOptions struct { // Language of the repo Verbose bool collect.CollectOption + // specify the repo id + RepoID string } func Parse(ctx context.Context, uri string, args ParseOptions) ([]byte, error) { @@ -78,6 +80,11 @@ func Parse(ctx context.Context, uri string, args ParseOptions) ([]byte, error) { return nil, err } log.Info("all symbols collected, start writing to stdout...\n") + + if args.RepoID != "" { + repo.Name = args.RepoID + } + out, err := json.Marshal(repo) if err != nil { log.Error("Failed to marshal repository: %v\n", err) diff --git a/main.go b/main.go index 53e026f..e91e789 100644 --- a/main.go +++ b/main.go @@ -51,48 +51,56 @@ Action: Language: rust for rust codes go for golang codes -URI: - for action parse: the directory path of the repo - for action write: the file path of the UniAST for writer ` func main() { flags := flag.NewFlagSet("abcoder", flag.ExitOnError) + + flagHelp := flags.Bool("h", false, "Show help message.") + + flagVerbose := flags.Bool("verbose", false, "Verbose mode.") + + flagOutput := flags.String("o", "", "Output path.") + + var opts lang.ParseOptions + flags.BoolVar(&opts.LoadExternalSymbol, "load-external-symbol", false, "load external symbols into results") + flags.BoolVar(&opts.NoNeedComment, "no-need-comment", false, "do not need comment (only works for Go now)") + flags.BoolVar(&opts.NeedTest, "need-test", false, "need parse test files (only works for Go now)") + flags.Var((*StringArray)(&opts.Excludes), "exclude", "exclude files or directories, support multiple values") + flags.StringVar(&opts.RepoID, "repo-id", "", "specify the repo id") + flagLsp := flags.String("lsp", "", "Specify the language server path.") + + var wopts lang.WriteOptions + flags.StringVar(&wopts.Compiler, "compiler", "", "destination compiler path.") + flags.Usage = func() { - fmt.Fprintf(os.Stderr, Usage) + fmt.Fprint(os.Stderr, Usage) fmt.Fprintf(os.Stderr, "Flags:\n") flags.PrintDefaults() } if len(os.Args) < 4 { - fmt.Fprintf(os.Stderr, Usage) + // call flags.Usage() + flags.Usage() os.Exit(1) } - action := strings.ToLower(os.Args[1]) language := uniast.NewLanguage(os.Args[2]) if language == uniast.Unknown { fmt.Fprintf(os.Stderr, "unsupported language: %s\n", os.Args[2]) os.Exit(1) } - uri := os.Args[3] - flagVerbose := flags.Bool("verbose", false, "Verbose mode.") - - flagOutput := flags.String("o", "", "Output path.") + flags.Parse(os.Args[4:]) + if flagHelp != nil && *flagHelp { + flags.Usage() + os.Exit(0) + } switch action { case "parse": - var opts lang.ParseOptions - - flags.BoolVar(&opts.LoadExternalSymbol, "load-external-symbol", false, "load external symbols into results") - flags.BoolVar(&opts.NoNeedComment, "no-need-comment", false, "do not need comment (only works for Go now)") - flags.BoolVar(&opts.NeedTest, "need-test", false, "need parse test files (only works for Go now)") - flags.Var((*StringArray)(&opts.Excludes), "exclude", "exclude files or directories, support multiple values") - flagLsp := flags.String("lsp", "", "Specify the language server path.") - flags.Parse(os.Args[4:]) if flagVerbose != nil && *flagVerbose { log.SetLogLevel(log.DebugLevel) opts.Verbose = true @@ -123,21 +131,16 @@ func main() { os.Exit(1) } - var opts lang.WriteOptions - flags.StringVar(&opts.Compiler, "compiler", "", "destination compiler path.") - - flags.Parse(os.Args[4:]) - if flagVerbose != nil && *flagVerbose { log.SetLogLevel(log.DebugLevel) } if flagOutput != nil && *flagOutput != "" { - opts.OutputDir = *flagOutput + wopts.OutputDir = *flagOutput } else { - opts.OutputDir = filepath.Base(repo.Name) + wopts.OutputDir = filepath.Base(repo.Name) } - if err := lang.Write(context.Background(), repo, opts); err != nil { + if err := lang.Write(context.Background(), repo, wopts); err != nil { log.Error("Failed to write: %v\n", err) os.Exit(1) } From 4674b324d21f87677b53fe6999281a1673247c28 Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Sun, 25 May 2025 17:14:35 +0800 Subject: [PATCH 2/3] opt:(uniast) add `json.Unmarshaler` to be compatible with old version --- lang/golang/parser/utils.go | 6 ++--- lang/uniast/ast.go | 52 ++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lang/golang/parser/utils.go b/lang/golang/parser/utils.go index eed93e3..204502e 100644 --- a/lang/golang/parser/utils.go +++ b/lang/golang/parser/utils.go @@ -175,11 +175,11 @@ func isPkgScope(scope *types.Scope) bool { func getTypeKind(n ast.Expr) TypeKind { switch n.(type) { case *ast.StructType: - return "struct" + return TypeKindStruct case *ast.InterfaceType: - return "interface" + return TypeKindInterface default: - return "typedef" + return TypeKindTypedef } } diff --git a/lang/uniast/ast.go b/lang/uniast/ast.go index 9f93694..f3d979c 100644 --- a/lang/uniast/ast.go +++ b/lang/uniast/ast.go @@ -17,9 +17,11 @@ package uniast import ( + "encoding/json" "fmt" "os" "path/filepath" + "strconv" "strings" ) @@ -103,6 +105,28 @@ type Import struct { Path string } +func (i *Import) UnmarshalJSON(data []byte) error { + if len(data) >= 2 && data[0] == '"' && data[len(data)-1] == '"' { + v, e := strconv.Unquote(string(data)) + if e != nil { + return e + } + i.Path = v + return nil + } else { + var ii importObj + err := json.Unmarshal(data, &ii) + if err != nil { + return err + } + i.Alias = ii.Alias + i.Path = ii.Path + return nil + } +} + +type importObj Import + func NewImport(alias *string, path string) Import { return Import{ Alias: alias, @@ -448,6 +472,31 @@ type FileLine struct { type TypeKind string +const ( + TypeKindStruct TypeKind = "struct" + TypeKindInterface TypeKind = "interface" + TypeKindTypedef TypeKind = "typedef" + TypeKindEnum TypeKind = "enum" +) + +func (t *TypeKind) UnmarshalJSON(data []byte) error { + if len(data) >= 2 && data[0] == '"' && data[len(data)-1] == '"' { + *t = TypeKind(data[1 : len(data)-1]) + return nil + } + + // 兼容历史go ast + switch string(data) { + case "0": + *t = TypeKindStruct + case "1": + *t = TypeKindInterface + default: + *t = TypeKindTypedef + } + return nil +} + // const ( // TypeKindStruct = 0 // type struct // TypeKindInterface = 1 // type interface @@ -459,7 +508,8 @@ type TypeKind string type Type struct { Exported bool // if the struct is exported - TypeKind // type Kind: Struct / Interface / Typedef + TypeKind TypeKind // type Kind: Struct / Interface / Typedef + Identity // unique id in a repo FileLine Content string // struct declaration content From 8d126c8d37e0f81bdaefe187a90c43405cdcc60f Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Sun, 25 May 2025 17:15:18 +0800 Subject: [PATCH 3/3] add recover back --- lang/golang/parser/file.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lang/golang/parser/file.go b/lang/golang/parser/file.go index 822ee70..b67a42a 100644 --- a/lang/golang/parser/file.go +++ b/lang/golang/parser/file.go @@ -29,13 +29,13 @@ import ( func (p *GoParser) parseFile(ctx *fileContext, f *ast.File) error { cont := true ast.Inspect(f, func(node ast.Node) bool { - // defer func() { - // if r := recover(); r != nil { - // fmt.Fprintf(os.Stderr, "panic: %v in %s:%d\n", r, ctx.filePath, ctx.fset.Position(node.Pos()).Line) - // cont = false - // return - // } - // }() + defer func() { + if r := recover(); r != nil { + fmt.Fprintf(os.Stderr, "panic: %v in %s:%d\n", r, ctx.filePath, ctx.fset.Position(node.Pos()).Line) + cont = false + return + } + }() if funcDecl, ok := node.(*ast.FuncDecl); ok { // parse funcs _, ct := p.parseFunc(ctx, funcDecl)