github.com/goplus/igop@v0.25.0/repl/pkg.go (about) 1 /* 2 * Copyright (c) 2022 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 repl 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "io" 24 "reflect" 25 "sort" 26 "strings" 27 28 "github.com/goplus/igop" 29 "github.com/goplus/igop/constant" 30 ) 31 32 // parseSymbol breaks str apart into a pkg, symbol and method 33 // fmt.Println => fmt Println 34 // fmt.Stringer.String => fmt Stringer.String 35 func parseSymbol(str string) (pkg, symbol string, method string, err error) { 36 if str == "" { 37 return 38 } 39 elem := strings.Split(str, ".") 40 switch len(elem) { 41 case 1: 42 case 2: 43 symbol = elem[1] 44 case 3: 45 symbol = elem[1] 46 method = elem[2] 47 default: 48 err = errors.New("too many periods in symbol specification") 49 return 50 } 51 pkg = elem[0] 52 return 53 } 54 55 func findPkg(name string) (pkg string, found bool) { 56 list := igop.PackageList() 57 for _, v := range list { 58 if name == v { 59 return v, true 60 } 61 } 62 for _, v := range list { 63 if strings.HasSuffix(v, "/"+name) { 64 return v, true 65 } 66 } 67 return 68 } 69 70 func lookupSymbol(p *igop.Package, sym string) (info string, found bool) { 71 if v, ok := p.UntypedConsts[sym]; ok { 72 return fmt.Sprintf("const %v.%v %v = %v", p.Name, sym, v.Typ, constant.ExactConstant(v.Value)), true 73 } 74 if v, ok := p.TypedConsts[sym]; ok { 75 return fmt.Sprintf("const %v.%v %v = %v", p.Name, sym, v.Typ, constant.ExactConstant(v.Value)), true 76 } 77 if v, ok := p.Vars[sym]; ok { 78 return fmt.Sprintf("var %v.%v %v", p.Name, sym, v.Type().Elem()), true 79 } 80 if v, ok := p.Funcs[sym]; ok { 81 var buf bytes.Buffer 82 writeFunc(&buf, p.Name+"."+sym, v.Type()) 83 return buf.String(), true 84 } 85 if t, ok := p.NamedTypes[sym]; ok { 86 var buf bytes.Buffer 87 if t.Kind() == reflect.Struct { 88 writeStruct(&buf, p.Name+"."+sym, t) 89 buf.WriteByte('\n') 90 } else { 91 fmt.Fprintf(&buf, "type %v.%v %v\n", p.Name, sym, t.Kind()) 92 } 93 n := t.NumMethod() 94 skip := make(map[string]bool) 95 for i := 0; i < n; i++ { 96 m := t.Method(i) 97 skip[m.Name] = true 98 writeMethod(&buf, m) 99 buf.WriteByte('\n') 100 } 101 ptyp := reflect.PtrTo(t) 102 n = ptyp.NumMethod() 103 for i := 0; i < n; i++ { 104 m := ptyp.Method(i) 105 if skip[m.Name] { 106 continue 107 } 108 writeMethod(&buf, m) 109 buf.WriteByte('\n') 110 } 111 return buf.String(), true 112 } 113 if t, ok := p.Interfaces[sym]; ok { 114 var buf bytes.Buffer 115 writeInterface(&buf, p.Name+"."+sym, t) 116 buf.WriteByte('\n') 117 return buf.String(), true 118 } 119 return 120 } 121 122 func dumpPkg(p *igop.Package) string { 123 var buf bytes.Buffer 124 fmt.Fprintf(&buf, "package %v // import %q\n\n", p.Name, p.Path) 125 // untyped const 126 var uconst []string 127 for v := range p.UntypedConsts { 128 uconst = append(uconst, v) 129 } 130 sort.Strings(uconst) 131 for _, v := range uconst { 132 t := p.UntypedConsts[v] 133 fmt.Fprintf(&buf, "const %v = %v\n", v, constant.ExactConstant(t.Value)) 134 } 135 // typed const 136 var tconst []string 137 for v := range p.TypedConsts { 138 tconst = append(tconst, v) 139 } 140 sort.Strings(tconst) 141 for _, v := range tconst { 142 t := p.TypedConsts[v] 143 fmt.Fprintf(&buf, "const %v %v = %v\n", v, t.Typ, constant.ExactConstant(t.Value)) 144 } 145 // var 146 var vars []string 147 for v := range p.Vars { 148 vars = append(vars, v) 149 } 150 sort.Strings(vars) 151 for _, v := range vars { 152 t := p.Vars[v] 153 fmt.Fprintf(&buf, "var %v %v\n", v, t.Elem().Type()) 154 } 155 // funcs 156 var funcs []string 157 for v := range p.Funcs { 158 funcs = append(funcs, v) 159 } 160 sort.Strings(funcs) 161 for _, v := range funcs { 162 f := p.Funcs[v] 163 writeFunc(&buf, v, f.Type()) 164 buf.WriteByte('\n') 165 } 166 // named types 167 var types []string 168 for v := range p.NamedTypes { 169 types = append(types, v) 170 } 171 sort.Strings(types) 172 for _, v := range types { 173 t := p.NamedTypes[v] 174 fmt.Fprintf(&buf, "type %v %v\n", v, t.Kind()) 175 skip := make(map[string]bool) 176 n := t.NumMethod() 177 for i := 0; i < n; i++ { 178 m := t.Method(i) 179 skip[m.Name] = true 180 buf.WriteString(" ") 181 writeMethod(&buf, m) 182 buf.WriteByte('\n') 183 } 184 ptyp := reflect.PtrTo(t) 185 n = ptyp.NumMethod() 186 for i := 0; i < n; i++ { 187 m := ptyp.Method(i) 188 if skip[m.Name] { 189 continue 190 } 191 buf.WriteString(" ") 192 writeMethod(&buf, m) 193 buf.WriteByte('\n') 194 } 195 } 196 // interface 197 var ifaces []string 198 for v := range p.Interfaces { 199 ifaces = append(ifaces, v) 200 } 201 sort.Strings(ifaces) 202 for _, v := range ifaces { 203 t := p.Interfaces[v] 204 fmt.Fprintf(&buf, "type %v interface\n", v) 205 n := t.NumMethod() 206 for i := 0; i < n; i++ { 207 m := t.Method(i) 208 buf.WriteString(" ") 209 writeFunc(&buf, m.Name, m.Type) 210 buf.WriteByte('\n') 211 } 212 } 213 return buf.String() 214 } 215 216 func writeInterface(w io.Writer, name string, typ reflect.Type) { 217 n := typ.NumMethod() 218 if n == 0 { 219 fmt.Fprintf(w, "type %v interface{}", name) 220 return 221 } 222 fmt.Fprintf(w, "type %v interface{\n", name) 223 for i := 0; i < n; i++ { 224 m := typ.Method(i) 225 w.Write([]byte(" ")) 226 writeFunc(w, m.Name, m.Type) 227 w.Write([]byte{'\n'}) 228 } 229 w.Write([]byte{'}'}) 230 } 231 232 func writeStruct(w io.Writer, name string, typ reflect.Type) { 233 n := typ.NumField() 234 if n == 0 { 235 fmt.Fprintf(w, "type %v struct{}", name) 236 return 237 } 238 fmt.Fprintf(w, "type %v struct{\n", name) 239 for i := 0; i < n; i++ { 240 f := typ.Field(i) 241 if f.PkgPath != "" { 242 fmt.Fprintf(w, " // ... other fields elided ...\n") 243 break 244 } 245 if f.Anonymous { 246 fmt.Fprintf(w, " %v\n", f.Type) 247 } else { 248 fmt.Fprintf(w, " %v %v\n", f.Name, f.Type) 249 } 250 } 251 fmt.Fprintf(w, "}") 252 } 253 254 func writeMethod(w io.Writer, m reflect.Method) { 255 typ := m.Type 256 numIn := typ.NumIn() 257 numOut := typ.NumOut() 258 var ins []string 259 if typ.IsVariadic() { 260 for i := 1; i < numIn-1; i++ { 261 ins = append(ins, typ.In(i).String()) 262 } 263 ins = append(ins, "..."+typ.In(numIn-1).Elem().String()) 264 } else { 265 for i := 1; i < numIn; i++ { 266 ins = append(ins, typ.In(i).String()) 267 } 268 } 269 switch numOut { 270 case 0: 271 fmt.Fprintf(w, "func (%v) %v(%v)", typ.In(0), m.Name, strings.Join(ins, ", ")) 272 case 1: 273 fmt.Fprintf(w, "func (%v) %v(%v) %v", typ.In(0), m.Name, strings.Join(ins, ", "), typ.Out(0).String()) 274 default: 275 var outs []string 276 for i := 0; i < numOut; i++ { 277 outs = append(outs, typ.Out(i).String()) 278 } 279 fmt.Fprintf(w, "func (%v) %v(%v) (%v)", typ.In(0), m.Name, strings.Join(ins, ", "), strings.Join(outs, ", ")) 280 } 281 } 282 283 func writeFunc(w io.Writer, name string, typ reflect.Type) { 284 numIn := typ.NumIn() 285 numOut := typ.NumOut() 286 var ins []string 287 if typ.IsVariadic() { 288 for i := 0; i < numIn-1; i++ { 289 ins = append(ins, typ.In(i).String()) 290 } 291 ins = append(ins, "..."+typ.In(numIn-1).Elem().String()) 292 } else { 293 for i := 0; i < numIn; i++ { 294 ins = append(ins, typ.In(i).String()) 295 } 296 } 297 switch numOut { 298 case 0: 299 fmt.Fprintf(w, "func %v(%v)", name, strings.Join(ins, ", ")) 300 case 1: 301 fmt.Fprintf(w, "func %v(%v) %v", name, strings.Join(ins, ", "), typ.Out(0).String()) 302 default: 303 var outs []string 304 for i := 0; i < numOut; i++ { 305 outs = append(outs, typ.Out(i).String()) 306 } 307 fmt.Fprintf(w, "func %v(%v) (%v)", name, strings.Join(ins, ", "), strings.Join(outs, ", ")) 308 } 309 }