github.com/traefik/yaegi@v0.15.1/interp/use.go (about)

     1  package interp
     2  
     3  import (
     4  	"flag"
     5  	"fmt"
     6  	"go/constant"
     7  	"log"
     8  	"math/bits"
     9  	"os"
    10  	"path"
    11  	"reflect"
    12  )
    13  
    14  // Symbols returns a map of interpreter exported symbol values for the given
    15  // import path. If the argument is the empty string, all known symbols are
    16  // returned.
    17  func (interp *Interpreter) Symbols(importPath string) Exports {
    18  	m := map[string]map[string]reflect.Value{}
    19  	interp.mutex.RLock()
    20  	defer interp.mutex.RUnlock()
    21  
    22  	for k, v := range interp.srcPkg {
    23  		if importPath != "" && k != importPath {
    24  			continue
    25  		}
    26  		syms := map[string]reflect.Value{}
    27  		for n, s := range v {
    28  			if !canExport(n) {
    29  				// Skip private non-exported symbols.
    30  				continue
    31  			}
    32  			switch s.kind {
    33  			case constSym:
    34  				syms[n] = s.rval
    35  			case funcSym:
    36  				syms[n] = genFunctionWrapper(s.node)(interp.frame)
    37  			case varSym:
    38  				syms[n] = interp.frame.data[s.index]
    39  			case typeSym:
    40  				syms[n] = reflect.New(s.typ.TypeOf())
    41  			}
    42  		}
    43  
    44  		if len(syms) > 0 {
    45  			m[k] = syms
    46  		}
    47  
    48  		if importPath != "" {
    49  			return m
    50  		}
    51  	}
    52  
    53  	if importPath != "" && len(m) > 0 {
    54  		return m
    55  	}
    56  
    57  	for k, v := range interp.binPkg {
    58  		if importPath != "" && k != importPath {
    59  			continue
    60  		}
    61  		m[k] = v
    62  		if importPath != "" {
    63  			return m
    64  		}
    65  	}
    66  
    67  	return m
    68  }
    69  
    70  // getWrapper returns the wrapper type of the corresponding interface, trying
    71  // first the composed ones, or nil if not found.
    72  func getWrapper(n *node, t reflect.Type) reflect.Type {
    73  	p, ok := n.interp.binPkg[t.PkgPath()]
    74  	if !ok {
    75  		return nil
    76  	}
    77  	w := p["_"+t.Name()]
    78  	lm := n.typ.methods()
    79  
    80  	// mapTypes may contain composed interfaces wrappers to test against, from
    81  	// most complex to simplest (guaranteed by construction of mapTypes). Find the
    82  	// first for which the interpreter type has all the methods.
    83  	for _, rt := range n.interp.mapTypes[w] {
    84  		match := true
    85  		for i := 1; i < rt.NumField(); i++ {
    86  			// The interpreter type must have all required wrapper methods.
    87  			if _, ok := lm[rt.Field(i).Name[1:]]; !ok {
    88  				match = false
    89  				break
    90  			}
    91  		}
    92  		if match {
    93  			return rt
    94  		}
    95  	}
    96  
    97  	// Otherwise return the direct "non-composed" interface.
    98  	return w.Type().Elem()
    99  }
   100  
   101  // Use loads binary runtime symbols in the interpreter context so
   102  // they can be used in interpreted code.
   103  func (interp *Interpreter) Use(values Exports) error {
   104  	for k, v := range values {
   105  		importPath := path.Dir(k)
   106  		packageName := path.Base(k)
   107  
   108  		if k == "." && v["MapTypes"].IsValid() {
   109  			// Use mapping for special interface wrappers.
   110  			for kk, vv := range v["MapTypes"].Interface().(map[reflect.Value][]reflect.Type) {
   111  				interp.mapTypes[kk] = vv
   112  			}
   113  			continue
   114  		}
   115  
   116  		if importPath == "." {
   117  			return fmt.Errorf("export path %[1]q is missing a package name; did you mean '%[1]s/%[1]s'?", k)
   118  		}
   119  
   120  		if importPath == selfPrefix {
   121  			interp.hooks.Parse(v)
   122  			continue
   123  		}
   124  
   125  		if interp.binPkg[importPath] == nil {
   126  			interp.binPkg[importPath] = make(map[string]reflect.Value)
   127  			interp.pkgNames[importPath] = packageName
   128  		}
   129  
   130  		for s, sym := range v {
   131  			interp.binPkg[importPath][s] = sym
   132  		}
   133  		if k == selfPath {
   134  			interp.binPkg[importPath]["Self"] = reflect.ValueOf(interp)
   135  		}
   136  	}
   137  
   138  	// Checks if input values correspond to stdlib packages by looking for one
   139  	// well known stdlib package path.
   140  	if _, ok := values["fmt/fmt"]; ok {
   141  		fixStdlib(interp)
   142  	}
   143  	return nil
   144  }
   145  
   146  // fixStdlib redefines interpreter stdlib symbols to use the standard input,
   147  // output and errror assigned to the interpreter. The changes are limited to
   148  // the interpreter only.
   149  // Note that it is possible to escape the virtualized stdio by
   150  // read/write directly to file descriptors 0, 1, 2.
   151  func fixStdlib(interp *Interpreter) {
   152  	p := interp.binPkg["fmt"]
   153  	if p == nil {
   154  		return
   155  	}
   156  
   157  	stdin, stdout, stderr := interp.stdin, interp.stdout, interp.stderr
   158  
   159  	p["Print"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fprint(stdout, a...) })
   160  	p["Printf"] = reflect.ValueOf(func(f string, a ...interface{}) (n int, err error) { return fmt.Fprintf(stdout, f, a...) })
   161  	p["Println"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fprintln(stdout, a...) })
   162  
   163  	p["Scan"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fscan(stdin, a...) })
   164  	p["Scanf"] = reflect.ValueOf(func(f string, a ...interface{}) (n int, err error) { return fmt.Fscanf(stdin, f, a...) })
   165  	p["Scanln"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fscanln(stdin, a...) })
   166  
   167  	// Update mapTypes to virtualized symbols as well.
   168  	interp.mapTypes[p["Print"]] = interp.mapTypes[reflect.ValueOf(fmt.Print)]
   169  	interp.mapTypes[p["Printf"]] = interp.mapTypes[reflect.ValueOf(fmt.Printf)]
   170  	interp.mapTypes[p["Println"]] = interp.mapTypes[reflect.ValueOf(fmt.Println)]
   171  	interp.mapTypes[p["Scan"]] = interp.mapTypes[reflect.ValueOf(fmt.Scan)]
   172  	interp.mapTypes[p["Scanf"]] = interp.mapTypes[reflect.ValueOf(fmt.Scanf)]
   173  	interp.mapTypes[p["Scanln"]] = interp.mapTypes[reflect.ValueOf(fmt.Scanln)]
   174  
   175  	if p = interp.binPkg["flag"]; p != nil {
   176  		c := flag.NewFlagSet(os.Args[0], flag.PanicOnError)
   177  		c.SetOutput(stderr)
   178  		p["CommandLine"] = reflect.ValueOf(&c).Elem()
   179  	}
   180  
   181  	if p = interp.binPkg["log"]; p != nil {
   182  		l := log.New(stderr, "", log.LstdFlags)
   183  		// Restrict Fatal symbols to panic instead of exit.
   184  		p["Fatal"] = reflect.ValueOf(l.Panic)
   185  		p["Fatalf"] = reflect.ValueOf(l.Panicf)
   186  		p["Fatalln"] = reflect.ValueOf(l.Panicln)
   187  
   188  		p["Flags"] = reflect.ValueOf(l.Flags)
   189  		p["Output"] = reflect.ValueOf(l.Output)
   190  		p["Panic"] = reflect.ValueOf(l.Panic)
   191  		p["Panicf"] = reflect.ValueOf(l.Panicf)
   192  		p["Panicln"] = reflect.ValueOf(l.Panicln)
   193  		p["Prefix"] = reflect.ValueOf(l.Prefix)
   194  		p["Print"] = reflect.ValueOf(l.Print)
   195  		p["Printf"] = reflect.ValueOf(l.Printf)
   196  		p["Println"] = reflect.ValueOf(l.Println)
   197  		p["SetFlags"] = reflect.ValueOf(l.SetFlags)
   198  		p["SetOutput"] = reflect.ValueOf(l.SetOutput)
   199  		p["SetPrefix"] = reflect.ValueOf(l.SetPrefix)
   200  		p["Writer"] = reflect.ValueOf(l.Writer)
   201  
   202  		// Update mapTypes to virtualized symbols as well.
   203  		interp.mapTypes[p["Print"]] = interp.mapTypes[reflect.ValueOf(log.Print)]
   204  		interp.mapTypes[p["Printf"]] = interp.mapTypes[reflect.ValueOf(log.Printf)]
   205  		interp.mapTypes[p["Println"]] = interp.mapTypes[reflect.ValueOf(log.Println)]
   206  		interp.mapTypes[p["Panic"]] = interp.mapTypes[reflect.ValueOf(log.Panic)]
   207  		interp.mapTypes[p["Panicf"]] = interp.mapTypes[reflect.ValueOf(log.Panicf)]
   208  		interp.mapTypes[p["Panicln"]] = interp.mapTypes[reflect.ValueOf(log.Panicln)]
   209  	}
   210  
   211  	if p = interp.binPkg["os"]; p != nil {
   212  		p["Args"] = reflect.ValueOf(&interp.args).Elem()
   213  		if interp.specialStdio {
   214  			// Inherit streams from interpreter even if they do not have a file descriptor.
   215  			p["Stdin"] = reflect.ValueOf(&stdin).Elem()
   216  			p["Stdout"] = reflect.ValueOf(&stdout).Elem()
   217  			p["Stderr"] = reflect.ValueOf(&stderr).Elem()
   218  		} else {
   219  			// Inherits streams from interpreter only if they have a file descriptor and preserve original type.
   220  			if s, ok := stdin.(*os.File); ok {
   221  				p["Stdin"] = reflect.ValueOf(&s).Elem()
   222  			}
   223  			if s, ok := stdout.(*os.File); ok {
   224  				p["Stdout"] = reflect.ValueOf(&s).Elem()
   225  			}
   226  			if s, ok := stderr.(*os.File); ok {
   227  				p["Stderr"] = reflect.ValueOf(&s).Elem()
   228  			}
   229  		}
   230  		if !interp.unrestricted {
   231  			// In restricted mode, scripts can only access to a passed virtualized env, and can not write the real one.
   232  			getenv := func(key string) string { return interp.env[key] }
   233  			p["Clearenv"] = reflect.ValueOf(func() { interp.env = map[string]string{} })
   234  			p["ExpandEnv"] = reflect.ValueOf(func(s string) string { return os.Expand(s, getenv) })
   235  			p["Getenv"] = reflect.ValueOf(getenv)
   236  			p["LookupEnv"] = reflect.ValueOf(func(key string) (s string, ok bool) { s, ok = interp.env[key]; return })
   237  			p["Setenv"] = reflect.ValueOf(func(key, value string) error { interp.env[key] = value; return nil })
   238  			p["Unsetenv"] = reflect.ValueOf(func(key string) error { delete(interp.env, key); return nil })
   239  			p["Environ"] = reflect.ValueOf(func() (a []string) {
   240  				for k, v := range interp.env {
   241  					a = append(a, k+"="+v)
   242  				}
   243  				return
   244  			})
   245  		}
   246  	}
   247  
   248  	if p = interp.binPkg["math/bits"]; p != nil {
   249  		// Do not trust extracted value maybe from another arch.
   250  		p["UintSize"] = reflect.ValueOf(constant.MakeInt64(bits.UintSize))
   251  	}
   252  }