github.com/goplus/gop@v1.2.6/x/format/gopstyle.go (about) 1 /* 2 * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package format 18 19 import ( 20 "bytes" 21 "go/types" 22 "path" 23 "strconv" 24 25 "github.com/goplus/gop/ast" 26 "github.com/goplus/gop/format" 27 "github.com/goplus/gop/parser" 28 "github.com/goplus/gop/token" 29 ) 30 31 // ----------------------------------------------------------------------------- 32 33 func GopstyleSource(src []byte, filename ...string) (ret []byte, err error) { 34 var fname string 35 if filename != nil { 36 fname = filename[0] 37 } 38 fset := token.NewFileSet() 39 var f *ast.File 40 if f, err = parser.ParseFile(fset, fname, src, parser.ParseComments); err == nil { 41 Gopstyle(f) 42 var buf bytes.Buffer 43 if err = format.Node(&buf, fset, f); err == nil { 44 ret = buf.Bytes() 45 } 46 } 47 return 48 } 49 50 // ----------------------------------------------------------------------------- 51 52 func Gopstyle(file *ast.File) { 53 if identEqual(file.Name, "main") { 54 file.NoPkgDecl = true 55 } 56 if idx, fn := findFuncDecl(file.Decls, "main"); idx >= 0 { 57 last := len(file.Decls) - 1 58 if idx == last { 59 file.ShadowEntry = fn 60 // TODO: idx != last: swap main func to last 61 // TODO: should also swap file.Comments 62 /* 63 fn := file.Decls[idx] 64 copy(file.Decls[idx:], file.Decls[idx+1:]) 65 file.Decls[last] = fn 66 */ 67 } 68 } 69 formatFile(file) 70 } 71 72 func findFuncDecl(decls []ast.Decl, name string) (int, *ast.FuncDecl) { 73 for i, decl := range decls { 74 if fn, ok := decl.(*ast.FuncDecl); ok { 75 if identEqual(fn.Name, name) { 76 return i, fn 77 } 78 } 79 } 80 return -1, nil 81 } 82 83 func findDecl(decls []ast.Decl, v ast.Decl) int { 84 for i, decl := range decls { 85 if decl == v { 86 return i 87 } 88 } 89 return -1 90 } 91 92 func findSpec(specs []ast.Spec, v ast.Spec) int { 93 for i, spec := range specs { 94 if spec == v { 95 return i 96 } 97 } 98 return -1 99 } 100 101 func deleteDecl(decls []ast.Decl, v ast.Decl) []ast.Decl { 102 if idx := findDecl(decls, v); idx >= 0 { 103 decls = append(decls[:idx], decls[idx+1:]...) 104 } 105 return decls 106 } 107 108 func deleteSpec(specs []ast.Spec, v ast.Spec) []ast.Spec { 109 if idx := findSpec(specs, v); idx >= 0 { 110 specs = append(specs[:idx], specs[idx+1:]...) 111 } 112 return specs 113 } 114 115 func startWithLowerCase(v *ast.Ident) { 116 if c := v.Name[0]; c >= 'A' && c <= 'Z' { 117 v.Name = string(c+('a'-'A')) + v.Name[1:] 118 } 119 } 120 121 func identEqual(v *ast.Ident, name string) bool { 122 return v != nil && v.Name == name 123 } 124 125 func toString(l *ast.BasicLit) string { 126 if l.Kind == token.STRING { 127 s, err := strconv.Unquote(l.Value) 128 if err == nil { 129 return s 130 } 131 } 132 panic("TODO: toString - convert ast.BasicLit to string failed") 133 } 134 135 // ----------------------------------------------------------------------------- 136 137 type importCtx struct { 138 pkgPath string 139 decl *ast.GenDecl 140 spec *ast.ImportSpec 141 isUsed bool 142 } 143 144 type formatCtx struct { 145 imports map[string]*importCtx 146 scope *types.Scope 147 } 148 149 func (ctx *formatCtx) insert(name string) { 150 o := types.NewParam(token.NoPos, nil, name, types.Typ[types.UntypedNil]) 151 ctx.scope.Insert(o) 152 } 153 154 func (ctx *formatCtx) enterBlock() *types.Scope { 155 old := ctx.scope 156 ctx.scope = types.NewScope(old, token.NoPos, token.NoPos, "") 157 return old 158 } 159 160 func (ctx *formatCtx) leaveBlock(old *types.Scope) { 161 ctx.scope = old 162 } 163 164 func formatFile(file *ast.File) { 165 var funcs []*ast.FuncDecl 166 ctx := &formatCtx{ 167 imports: make(map[string]*importCtx), 168 scope: types.NewScope(nil, token.NoPos, token.NoPos, ""), 169 } 170 for _, decl := range file.Decls { 171 switch v := decl.(type) { 172 case *ast.FuncDecl: 173 // delay the process, because package level vars need to be processed first. 174 funcs = append(funcs, v) 175 case *ast.GenDecl: 176 switch v.Tok { 177 case token.IMPORT: 178 for _, item := range v.Specs { 179 var spec = item.(*ast.ImportSpec) 180 var pkgPath = toString(spec.Path) 181 var name string 182 if spec.Name == nil { 183 name = path.Base(pkgPath) // TODO: open pkgPath to get pkgName 184 } else { 185 name = spec.Name.Name 186 if name == "." || name == "_" { 187 continue 188 } 189 } 190 ctx.imports[name] = &importCtx{pkgPath: pkgPath, decl: v, spec: spec} 191 } 192 default: 193 formatGenDecl(ctx, v) 194 } 195 } 196 } 197 198 for _, fn := range funcs { 199 formatFuncDecl(ctx, fn) 200 } 201 for _, imp := range ctx.imports { 202 if imp.pkgPath == "fmt" && !imp.isUsed { 203 if len(imp.decl.Specs) == 1 { 204 file.Decls = deleteDecl(file.Decls, imp.decl) 205 } else { 206 imp.decl.Specs = deleteSpec(imp.decl.Specs, imp.spec) 207 } 208 } 209 } 210 } 211 212 func formatGenDecl(ctx *formatCtx, v *ast.GenDecl) { 213 switch v.Tok { 214 case token.VAR, token.CONST: 215 for _, item := range v.Specs { 216 spec := item.(*ast.ValueSpec) 217 formatType(ctx, spec.Type, &spec.Type) 218 formatExprs(ctx, spec.Values) 219 for _, name := range spec.Names { 220 ctx.insert(name.Name) 221 } 222 } 223 case token.TYPE: 224 for _, item := range v.Specs { 225 spec := item.(*ast.TypeSpec) 226 formatType(ctx, spec.Type, &spec.Type) 227 } 228 } 229 } 230 231 func formatFuncDecl(ctx *formatCtx, v *ast.FuncDecl) { 232 formatFuncType(ctx, v.Type) 233 formatBlockStmt(ctx, v.Body) 234 } 235 236 /* 237 func fillVarCtx(ctx *formatCtx, spec *ast.ValueSpec) { 238 for _, name := range spec.Names { 239 ctx.scp.addVar(name.Name) 240 } 241 } 242 243 type scope struct { 244 vars []map[string]bool 245 } 246 247 func newScope() *scope { 248 return &scope{ 249 vars: []map[string]bool{make(map[string]bool)}, 250 } 251 } 252 253 func (s *scope) addVar(name string) { 254 s.vars[len(s.vars)-1][name] = true 255 } 256 257 func (s *scope) containsVar(name string) bool { 258 for _, m := range s.vars { 259 if m[name] { 260 return true 261 } 262 } 263 264 return false 265 } 266 267 func (s *scope) enterScope() { 268 s.vars = append(s.vars, make(map[string]bool)) 269 } 270 271 func (s *scope) exitScope() { 272 s.vars = s.vars[:len(s.vars)-1] 273 } 274 */ 275 // -----------------------------------------------------------------------------