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

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/importer"
     7  	"go/types"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  func (a *goAST) checkType() {
    13  	var (
    14  		info = types.Info{
    15  			Types: make(map[ast.Expr]types.TypeAndValue),
    16  			Defs:  make(map[*ast.Ident]types.Object),
    17  			Uses:  make(map[*ast.Ident]types.Object),
    18  		}
    19  		conf = types.Config{
    20  			Importer: importer.ForCompiler(a.fset, "source", nil),
    21  			// DisableUnusedImportCheck: true,
    22  			Error: func(err error) {
    23  				if sl := strings.Split(err.Error(), "could not import"); len(sl) == 2 {
    24  					fmt.Printf("\n Error: could not import%s\n\n", sl[1])
    25  				}
    26  			},
    27  		}
    28  	)
    29  	conf.Check("check", a.fset, []*ast.File{a.node}, &info)
    30  
    31  	ast.Inspect(a.node, func(n ast.Node) bool {
    32  		if n != nil {
    33  			switch x := n.(type) {
    34  			case *ast.CaseClause:
    35  				rewrite(x.Body, &info)
    36  			case *ast.BlockStmt:
    37  				rewrite(x.List, &info)
    38  				// case *ast.CallExpr:
    39  				// return false
    40  			}
    41  		}
    42  		return true
    43  	})
    44  }
    45  
    46  //
    47  
    48  func rewrite(in []ast.Stmt, info *types.Info) {
    49  	for k, ex := range in {
    50  		if d, ok := ex.(*ast.DeclStmt); ok {
    51  			if s, ok := d.Decl.(*ast.GenDecl); ok && len(s.Specs) == 1 {
    52  				if v, ok := s.Specs[0].(*ast.ValueSpec); ok && len(v.Names) == 1 {
    53  					var escape bool
    54  
    55  					switch {
    56  					case strings.HasPrefix(v.Names[0].Name, "esc"):
    57  						escape = true
    58  					case strings.HasPrefix(v.Names[0].Name, "unesc"):
    59  						escape = false
    60  					default:
    61  						continue
    62  					}
    63  
    64  					switch vt := info.TypeOf(v.Values[0]).(type) {
    65  					case *types.Basic:
    66  						if stdlib {
    67  							switch vt.Name() {
    68  							case "string":
    69  								in[k] = stdlibFuncCall(escape, "", "", arg(v.Values[0]))
    70  							case "int", "int8", "int16", "int32":
    71  								in[k] = stdlibFuncCall(escape, "strconv", "FormatInt", arg(funcCall("", "int64", arg(v.Values[0])), a("10")))
    72  							case "int64":
    73  								in[k] = stdlibFuncCall(escape, "strconv", "FormatInt", arg(v.Values[0], a("10")))
    74  							case "uint", "uint8", "uint16", "uint32":
    75  								in[k] = stdlibFuncCall(escape, "strconv", "FormatUint", arg(funcCall("", "uint64", arg(v.Values[0])), a("10")))
    76  							case "uint64":
    77  								in[k] = stdlibFuncCall(escape, "strconv", "FormatUint", arg(v.Values[0], a("10")))
    78  							case "bool":
    79  								in[k] = stdlibFuncCall(escape, "strconv", "FormatBool", arg(v.Values[0]))
    80  							case "float64":
    81  								in[k] = stdlibFuncCall(escape, "strconv", "FormatFloat", arg(v.Values[0], a("'f'"), &ast.UnaryExpr{Op: 13, X: a("1")}, a("64"))) // &ast.UnaryExpr{Op: 13, X: a("1")} =>= -1
    82  							default:
    83  								in[k] = stdlibFuncCall(escape, "fmt", "Sprintf", arg(a(`"%v"`), v.Values[0]))
    84  							}
    85  						} else {
    86  							switch vt.Name() {
    87  							case "string":
    88  								if escape {
    89  									in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteEscString", arg(v.Values[0], a("buffer")))}
    90  								} else {
    91  									in[k] = &ast.ExprStmt{X: funcCall("buffer", "WriteString", arg(v.Values[0]))}
    92  								}
    93  							case "int", "int8", "int16", "int32":
    94  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteInt", arg(funcCall("", "int64", arg(v.Values[0])), a("buffer")))}
    95  							case "int64":
    96  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteInt", arg(v.Values[0], a("buffer")))}
    97  							case "uint", "uint8", "uint16", "uint32":
    98  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteUint", arg(funcCall("", "uint64", arg(v.Values[0])), a("buffer")))}
    99  							case "uint64":
   100  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteUint", arg(v.Values[0], a("buffer")))}
   101  							case "bool":
   102  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteBool", arg(v.Values[0], a("buffer")))}
   103  							case "float64":
   104  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteFloat", arg(v.Values[0], a("buffer")))}
   105  							default:
   106  								in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteAll", arg(v.Values[0], a(strconv.FormatBool(escape)), a("buffer")))}
   107  							}
   108  						}
   109  					default:
   110  						if stdlib {
   111  							in[k] = stdlibFuncCall(escape, "fmt", "Sprintf", arg(a(`"%v"`), v.Values[0]))
   112  						} else {
   113  							in[k] = &ast.ExprStmt{X: funcCall(lib_name, "WriteAll", arg(v.Values[0], a(strconv.FormatBool(escape)), a("buffer")))}
   114  						}
   115  					}
   116  				}
   117  			}
   118  		}
   119  	}
   120  }
   121  
   122  func stdlibFuncCall(esc bool, x, sel string, exps []ast.Expr) *ast.ExprStmt {
   123  	arg := exps
   124  	if sel != "" {
   125  		arg = []ast.Expr{funcCall(x, sel, exps)}
   126  	}
   127  	if esc {
   128  		return &ast.ExprStmt{X: funcCall("buffer", "WriteString", []ast.Expr{funcCall("html", "EscapeString", arg)})}
   129  	} else {
   130  		return &ast.ExprStmt{X: funcCall("buffer", "WriteString", arg)}
   131  	}
   132  }
   133  
   134  //
   135  
   136  func funcCall(packName, funcName string, exps []ast.Expr) *ast.CallExpr {
   137  	if packName == "" {
   138  		return &ast.CallExpr{
   139  			Fun: &ast.Ident{
   140  				Name: funcName,
   141  			},
   142  			Args: exps,
   143  		}
   144  	}
   145  	return &ast.CallExpr{
   146  		Fun: &ast.SelectorExpr{
   147  			X:   &ast.Ident{Name: packName},
   148  			Sel: &ast.Ident{Name: funcName},
   149  		},
   150  		Args: exps,
   151  	}
   152  }
   153  
   154  func arg(i ...ast.Expr) []ast.Expr { return i }
   155  func a(i string) *ast.BasicLit     { return &ast.BasicLit{Value: i} }