123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- package ast
- import (
- "fmt"
- "sort"
- "strings"
- "github.com/antlr/antlr4/runtime/Go/antlr"
- "github.com/tal-tech/go-zero/tools/goctl/api/parser/g4/gen/api"
- "github.com/tal-tech/go-zero/tools/goctl/util/console"
- )
- type (
- // TokenStream defines a token
- TokenStream interface {
- GetStart() antlr.Token
- GetStop() antlr.Token
- GetParser() antlr.Parser
- }
- // ApiVisitor wraps api.BaseApiParserVisitor to call methods which has prefix Visit to
- // visit node from the api syntax
- ApiVisitor struct {
- api.BaseApiParserVisitor
- debug bool
- log console.Console
- prefix string
- infoFlag bool
- }
- // VisitorOption defines a function with argument ApiVisitor
- VisitorOption func(v *ApiVisitor)
- // Spec describes api spec
- Spec interface {
- Doc() []Expr
- Comment() Expr
- Format() error
- Equal(v interface{}) bool
- }
- // Expr describes ast expression
- Expr interface {
- Prefix() string
- Line() int
- Column() int
- Text() string
- SetText(text string)
- Start() int
- Stop() int
- Equal(expr Expr) bool
- IsNotNil() bool
- }
- )
- // NewApiVisitor creates an instance for ApiVisitor
- func NewApiVisitor(options ...VisitorOption) *ApiVisitor {
- v := &ApiVisitor{
- log: console.NewColorConsole(),
- }
- for _, opt := range options {
- opt(v)
- }
- return v
- }
- func (v *ApiVisitor) panic(expr Expr, msg string) {
- errString := fmt.Sprintf("%s line %d:%d %s", v.prefix, expr.Line(), expr.Column(), msg)
- if v.debug {
- fmt.Println(errString)
- }
- panic(errString)
- }
- // WithVisitorPrefix returns a VisitorOption wrap with specified prefix
- func WithVisitorPrefix(prefix string) VisitorOption {
- return func(v *ApiVisitor) {
- v.prefix = prefix
- }
- }
- // WithVisitorDebug returns a debug VisitorOption
- func WithVisitorDebug() VisitorOption {
- return func(v *ApiVisitor) {
- v.debug = true
- }
- }
- type defaultExpr struct {
- prefix, v string
- line, column int
- start, stop int
- }
- // NewTextExpr creates a default instance for Expr
- func NewTextExpr(v string) *defaultExpr {
- return &defaultExpr{
- v: v,
- }
- }
- func (v *ApiVisitor) newExprWithTerminalNode(node antlr.TerminalNode) *defaultExpr {
- if node == nil {
- return nil
- }
- token := node.GetSymbol()
- return v.newExprWithToken(token)
- }
- func (v *ApiVisitor) newExprWithToken(token antlr.Token) *defaultExpr {
- if token == nil {
- return nil
- }
- instance := &defaultExpr{}
- instance.prefix = v.prefix
- instance.v = token.GetText()
- instance.line = token.GetLine()
- instance.column = token.GetColumn()
- instance.start = token.GetStart()
- instance.stop = token.GetStop()
- return instance
- }
- func (v *ApiVisitor) newExprWithText(text string, line, column, start, stop int) *defaultExpr {
- instance := &defaultExpr{}
- instance.prefix = v.prefix
- instance.v = text
- instance.line = line
- instance.column = column
- instance.start = start
- instance.stop = stop
- return instance
- }
- func (e *defaultExpr) Prefix() string {
- if e == nil {
- return ""
- }
- return e.prefix
- }
- func (e *defaultExpr) Line() int {
- if e == nil {
- return 0
- }
- return e.line
- }
- func (e *defaultExpr) Column() int {
- if e == nil {
- return 0
- }
- return e.column
- }
- func (e *defaultExpr) Text() string {
- if e == nil {
- return ""
- }
- return e.v
- }
- func (e *defaultExpr) SetText(text string) {
- if e == nil {
- return
- }
- e.v = text
- }
- func (e *defaultExpr) Start() int {
- if e == nil {
- return 0
- }
- return e.start
- }
- func (e *defaultExpr) Stop() int {
- if e == nil {
- return 0
- }
- return e.stop
- }
- func (e *defaultExpr) Equal(expr Expr) bool {
- if e == nil {
- if expr != nil {
- return false
- }
- return true
- }
- if expr == nil {
- return false
- }
- return e.v == expr.Text()
- }
- func (e *defaultExpr) IsNotNil() bool {
- return e != nil
- }
- // EqualDoc compares whether the element literals in two Spec are equal
- func EqualDoc(spec1, spec2 Spec) bool {
- if spec1 == nil {
- return spec2 == nil
- }
- if spec2 == nil {
- return false
- }
- var expectDoc, actualDoc []Expr
- expectDoc = append(expectDoc, spec2.Doc()...)
- actualDoc = append(actualDoc, spec1.Doc()...)
- sort.Slice(expectDoc, func(i, j int) bool {
- return expectDoc[i].Line() < expectDoc[j].Line()
- })
- for index, each := range actualDoc {
- if !each.Equal(actualDoc[index]) {
- return false
- }
- }
- if spec1.Comment() != nil {
- if spec2.Comment() == nil {
- return false
- }
- if !spec1.Comment().Equal(spec2.Comment()) {
- return false
- }
- } else {
- if spec2.Comment() != nil {
- return false
- }
- }
- return true
- }
- func (v *ApiVisitor) getDoc(t TokenStream) []Expr {
- list := v.getHiddenTokensToLeft(t, api.COMEMNTS, false)
- return list
- }
- func (v *ApiVisitor) getComment(t TokenStream) Expr {
- list := v.getHiddenTokensToRight(t, api.COMEMNTS)
- if len(list) == 0 {
- return nil
- }
- commentExpr := list[0]
- stop := t.GetStop()
- text := stop.GetText()
- nlCount := strings.Count(text, "\n")
- if commentExpr.Line() != stop.GetLine()+nlCount {
- return nil
- }
- return commentExpr
- }
- func (v *ApiVisitor) getHiddenTokensToLeft(t TokenStream, channel int, containsCommentOfDefaultChannel bool) []Expr {
- ct := t.GetParser().GetTokenStream().(*antlr.CommonTokenStream)
- tokens := ct.GetHiddenTokensToLeft(t.GetStart().GetTokenIndex(), channel)
- var tmp []antlr.Token
- for _, each := range tokens {
- tmp = append(tmp, each)
- }
- var list []Expr
- for _, each := range tmp {
- if !containsCommentOfDefaultChannel {
- index := each.GetTokenIndex() - 1
- if index > 0 {
- allTokens := ct.GetAllTokens()
- flag := false
- for i := index; i >= 0; i-- {
- tk := allTokens[i]
- if tk.GetChannel() == antlr.LexerDefaultTokenChannel {
- if tk.GetLine() == each.GetLine() {
- flag = true
- break
- }
- }
- }
- if flag {
- continue
- }
- }
- }
- list = append(list, v.newExprWithToken(each))
- }
- return list
- }
- func (v *ApiVisitor) getHiddenTokensToRight(t TokenStream, channel int) []Expr {
- ct := t.GetParser().GetTokenStream().(*antlr.CommonTokenStream)
- tokens := ct.GetHiddenTokensToRight(t.GetStop().GetTokenIndex(), channel)
- var list []Expr
- for _, each := range tokens {
- list = append(list, v.newExprWithToken(each))
- }
- return list
- }
|