123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- package ast
- import (
- "bytes"
- "fmt"
- "io"
- "strings"
- "text/tabwriter"
- "github.com/zeromicro/go-zero/tools/goctl/pkg/parser/api/token"
- "github.com/zeromicro/go-zero/tools/goctl/util"
- )
- const (
- NilIndent = ""
- WhiteSpace = " "
- Indent = "\t"
- NewLine = "\n"
- )
- const (
- _ WriteMode = 1 << iota
- // ModeAuto is the default mode, which will automatically
- //determine whether to write a newline.
- ModeAuto
- // ModeExpectInSameLine will write in the same line.
- ModeExpectInSameLine
- )
- type Option func(o *option)
- type option struct {
- prefix string
- infix string
- mode WriteMode
- nodes []Node
- rawText bool
- }
- type tokenNodeOption func(o *tokenNodeOpt)
- type tokenNodeOpt struct {
- prefix string
- infix string
- ignoreHeadComment bool
- ignoreLeadingComment bool
- }
- // WriteMode is the mode of writing.
- type WriteMode int
- // Writer is the writer of ast.
- type Writer struct {
- tw *tabwriter.Writer
- writer io.Writer
- }
- func transfer2TokenNode(node Node, isChild bool, opt ...tokenNodeOption) *TokenNode {
- option := new(tokenNodeOpt)
- for _, o := range opt {
- o(option)
- }
- var copyOpt = append([]tokenNodeOption(nil), opt...)
- var tn *TokenNode
- switch val := node.(type) {
- case *AnyDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.Any, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.Any = tn
- case *ArrayDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.LBrack, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.LBrack = tn
- case *BaseDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.Base, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.Base = tn
- case *InterfaceDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.Interface, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.Interface = tn
- case *MapDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.Map, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.Map = tn
- case *PointerDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.Star, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.Star = tn
- case *SliceDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.LBrack, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.LBrack = tn
- case *StructDataType:
- copyOpt = append(copyOpt, withTokenNodePrefix(NilIndent))
- tn = transferTokenNode(val.LBrace, copyOpt...)
- if option.ignoreHeadComment {
- tn.HeadCommentGroup = nil
- }
- if option.ignoreLeadingComment {
- tn.LeadingCommentGroup = nil
- }
- val.isChild = isChild
- val.LBrace = tn
- default:
- }
- return &TokenNode{
- headFlag: node.HasHeadCommentGroup(),
- leadingFlag: node.HasLeadingCommentGroup(),
- Token: token.Token{
- Text: node.Format(option.prefix),
- Position: node.Pos(),
- },
- LeadingCommentGroup: CommentGroup{
- {
- token.Token{Position: node.End()},
- },
- },
- }
- }
- func transferNilInfixNode(nodes []*TokenNode, opt ...tokenNodeOption) *TokenNode {
- result := &TokenNode{}
- var option = new(tokenNodeOpt)
- for _, o := range opt {
- o(option)
- }
- var list []string
- for _, n := range nodes {
- list = append(list, n.Token.Text)
- }
- result.Token = token.Token{
- Text: option.prefix + strings.Join(list, option.infix),
- Position: nodes[0].Pos(),
- }
- if !option.ignoreHeadComment {
- result.HeadCommentGroup = nodes[0].HeadCommentGroup
- }
- if !option.ignoreLeadingComment {
- result.LeadingCommentGroup = nodes[len(nodes)-1].LeadingCommentGroup
- }
- return result
- }
- func transferTokenNode(node *TokenNode, opt ...tokenNodeOption) *TokenNode {
- result := &TokenNode{}
- var option = new(tokenNodeOpt)
- for _, o := range opt {
- o(option)
- }
- result.Token = token.Token{
- Type: node.Token.Type,
- Text: option.prefix + node.Token.Text,
- Position: node.Token.Position,
- }
- if !option.ignoreHeadComment {
- for _, v := range node.HeadCommentGroup {
- result.HeadCommentGroup = append(result.HeadCommentGroup,
- &CommentStmt{Comment: token.Token{
- Type: v.Comment.Type,
- Text: option.prefix + v.Comment.Text,
- Position: v.Comment.Position,
- }})
- }
- }
- if !option.ignoreLeadingComment {
- for _, v := range node.LeadingCommentGroup {
- result.LeadingCommentGroup = append(result.LeadingCommentGroup, v)
- }
- }
- return result
- }
- func ignoreHeadComment() tokenNodeOption {
- return func(o *tokenNodeOpt) {
- o.ignoreHeadComment = true
- }
- }
- func ignoreLeadingComment() tokenNodeOption {
- return func(o *tokenNodeOpt) {
- o.ignoreLeadingComment = true
- }
- }
- func ignoreComment() tokenNodeOption {
- return func(o *tokenNodeOpt) {
- o.ignoreHeadComment = true
- o.ignoreLeadingComment = true
- }
- }
- func withTokenNodePrefix(prefix ...string) tokenNodeOption {
- return func(o *tokenNodeOpt) {
- for _, p := range prefix {
- o.prefix = p
- }
- }
- }
- func withTokenNodeInfix(infix string) tokenNodeOption {
- return func(o *tokenNodeOpt) {
- o.infix = infix
- }
- }
- func expectSameLine() Option {
- return func(o *option) {
- o.mode = ModeExpectInSameLine
- }
- }
- func expectIndentInfix() Option {
- return func(o *option) {
- o.infix = Indent
- }
- }
- func withNode(nodes ...Node) Option {
- return func(o *option) {
- o.nodes = nodes
- }
- }
- func withMode(mode WriteMode) Option {
- return func(o *option) {
- o.mode = mode
- }
- }
- func withPrefix(prefix ...string) Option {
- return func(o *option) {
- for _, p := range prefix {
- o.prefix = p
- }
- }
- }
- func withInfix(infix string) Option {
- return func(o *option) {
- o.infix = infix
- }
- }
- func withRawText() Option {
- return func(o *option) {
- o.rawText = true
- }
- }
- // NewWriter returns a new Writer.
- func NewWriter(writer io.Writer) *Writer {
- return &Writer{
- tw: tabwriter.NewWriter(writer, 1, 8, 1, ' ', tabwriter.TabIndent),
- writer: writer,
- }
- }
- // NewBufferWriter returns a new buffer Writer.
- func NewBufferWriter() *Writer {
- writer := bytes.NewBuffer(nil)
- return &Writer{
- tw: tabwriter.NewWriter(writer, 1, 8, 1, ' ', tabwriter.TabIndent),
- writer: writer,
- }
- }
- // String returns the string of the buffer.
- func (w *Writer) String() string {
- buffer, ok := w.writer.(*bytes.Buffer)
- if !ok {
- return ""
- }
- w.Flush()
- return buffer.String()
- }
- // Flush flushes the buffer.
- func (w *Writer) Flush() {
- _ = w.tw.Flush()
- }
- // NewLine writes a new line.
- func (w *Writer) NewLine() {
- _, _ = fmt.Fprint(w.tw, NewLine)
- }
- // Write writes the node.
- func (w *Writer) Write(opts ...Option) {
- if len(opts) == 0 {
- return
- }
- var opt = new(option)
- opt.mode = ModeAuto
- opt.prefix = NilIndent
- opt.infix = WhiteSpace
- for _, v := range opts {
- v(opt)
- }
- w.write(opt)
- }
- // WriteText writes the text.
- func (w *Writer) WriteText(text string) {
- _, _ = fmt.Fprintf(w.tw, text)
- }
- func (w *Writer) write(opt *option) {
- if len(opt.nodes) == 0 {
- return
- }
- var textList []string
- line := opt.nodes[0].End().Line
- for idx, node := range opt.nodes {
- mode := opt.mode
- preIdx := idx - 1
- var preNodeHasLeading bool
- if preIdx > -1 && preIdx < len(opt.nodes) {
- preNode := opt.nodes[preIdx]
- preNodeHasLeading = preNode.HasLeadingCommentGroup()
- }
- if node.HasHeadCommentGroup() || preNodeHasLeading {
- mode = ModeAuto
- }
- if mode == ModeAuto && node.Pos().Line > line {
- textList = append(textList, NewLine)
- }
- line = node.End().Line
- if util.TrimWhiteSpace(node.Format()) == "" {
- continue
- }
- textList = append(textList, node.Format(opt.prefix))
- }
- text := strings.Join(textList, opt.infix)
- text = strings.ReplaceAll(text, " \n", "\n")
- text = strings.ReplaceAll(text, "\n ", "\n")
- if opt.rawText {
- _, _ = fmt.Fprint(w.writer, text)
- return
- }
- _, _ = fmt.Fprint(w.tw, text)
- }
|