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  }