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 }