github.com/servernoj/jade@v0.0.0-20231225191405-efec98d19db1/cmd/jade/go_ast_wstr.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/ast"
     7  	"strings"
     8  )
     9  
    10  func (a *goAST) collapseWriteString(strInline bool, constName string) {
    11  	// ast.Print(a.fset, a.node)
    12  
    13  	var wrSt = writeStrings{inline: strInline, constName: constName}
    14  	ast.Inspect(a.node, func(n ast.Node) bool {
    15  		if n != nil {
    16  			switch x := n.(type) {
    17  			case *ast.CaseClause:
    18  				wrSt.push(x.Body)
    19  			case *ast.BlockStmt:
    20  				wrSt.push(x.List)
    21  				// case *ast.CallExpr:
    22  				// return false
    23  			}
    24  		}
    25  		return true
    26  	})
    27  
    28  	wrSt.fillConstNode(a.node.Decls)
    29  }
    30  
    31  //
    32  
    33  type writeStrings struct {
    34  	constSlice []struct {
    35  		str  string
    36  		name string
    37  	}
    38  	constName  string
    39  	constCount int
    40  	inline     bool
    41  }
    42  
    43  func (ws *writeStrings) push(in []ast.Stmt) {
    44  	type wStr struct {
    45  		s string
    46  		a *ast.CallExpr
    47  		z *ast.Stmt
    48  	}
    49  	List := [][]wStr{}
    50  	subList := make([]wStr, 0, 4)
    51  
    52  	for k, ex := range in {
    53  		if es, ok := ex.(*ast.ExprStmt); ok {
    54  			if ce, ok := es.X.(*ast.CallExpr); ok {
    55  				if fun, ok := ce.Fun.(*ast.SelectorExpr); ok && len(ce.Args) == 1 && fun.Sel.Name == "WriteString" {
    56  					if arg, ok := ce.Args[0].(*ast.BasicLit); ok {
    57  						subList = append(subList, wStr{s: strings.Trim(arg.Value, "`"), a: ce, z: &in[k]})
    58  						continue
    59  					}
    60  				}
    61  			}
    62  		}
    63  		if len(subList) > 0 {
    64  			List = append(List, subList)
    65  			subList = make([]wStr, 0, 4)
    66  		}
    67  	}
    68  	if len(subList) > 0 {
    69  		List = append(List, subList)
    70  	}
    71  
    72  	//
    73  
    74  	var st = new(bytes.Buffer)
    75  	for _, block := range List {
    76  
    77  		st.WriteString(block[0].s)
    78  		for i := 1; i < len(block); i++ {
    79  			st.WriteString(block[i].s)
    80  			*block[i].z = new(ast.EmptyStmt) // remove a node
    81  		}
    82  
    83  		if ws.inline {
    84  			block[0].a.Args[0].(*ast.BasicLit).Value = "`" + st.String() + "`"
    85  		} else {
    86  			str := st.String()
    87  			if name, ok := dict[str]; ok {
    88  				block[0].a.Args = []ast.Expr{&ast.Ident{Name: name}}
    89  			} else {
    90  				newName := fmt.Sprintf("%s__%d", ws.constName, ws.constCount)
    91  				block[0].a.Args = []ast.Expr{&ast.Ident{Name: newName}}
    92  				dict[str] = newName
    93  				ws.constSlice = append(ws.constSlice, struct {
    94  					str  string
    95  					name string
    96  				}{
    97  					str,
    98  					newName,
    99  				})
   100  			}
   101  		}
   102  
   103  		st.Reset()
   104  		ws.constCount += 1
   105  	}
   106  }
   107  
   108  func (ws *writeStrings) fillConstNode(decl []ast.Decl) {
   109  	if constNode, ok := decl[1].(*ast.GenDecl); ok && !ws.inline {
   110  		for _, v := range ws.constSlice {
   111  			constNode.Specs = append(constNode.Specs, &ast.ValueSpec{
   112  				Names: []*ast.Ident{
   113  					&ast.Ident{Name: v.name},
   114  				},
   115  				Values: []ast.Expr{
   116  					&ast.BasicLit{Kind: 9, Value: "`" + v.str + "`"}, // 9 => string
   117  				},
   118  			})
   119  		}
   120  	}
   121  }