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} }