github.com/HaHadaxigua/yaegi@v1.0.1/interp/interp.go (about) 1 package interp 2 3 import ( 4 "bufio" 5 "context" 6 "errors" 7 "flag" 8 "fmt" 9 "go/build" 10 "go/constant" 11 "go/scanner" 12 "go/token" 13 "io" 14 "io/fs" 15 "log" 16 "math/bits" 17 "os" 18 "os/signal" 19 "path" 20 "path/filepath" 21 "reflect" 22 "runtime" 23 "runtime/debug" 24 "strconv" 25 "strings" 26 "sync" 27 "sync/atomic" 28 ) 29 30 // Interpreter node structure for AST and CFG. 31 type node struct { 32 debug *nodeDebugData // debug info 33 child []*node // child subtrees (AST) 34 anc *node // ancestor (AST) 35 start *node // entry point in subtree (CFG) 36 tnext *node // true branch successor (CFG) 37 fnext *node // false branch successor (CFG) 38 interp *Interpreter // interpreter context 39 frame *frame // frame pointer used for closures only (TODO: suppress this) 40 index int64 // node index (dot display) 41 findex int // index of value in frame or frame size (func def, type def) 42 level int // number of frame indirections to access value 43 nleft int // number of children in left part (assign) or indicates preceding type (compositeLit) 44 nright int // number of children in right part (assign) 45 kind nkind // kind of node 46 pos token.Pos // position in source code, relative to fset 47 sym *symbol // associated symbol 48 typ *itype // type of value in frame, or nil 49 recv *receiver // method receiver node for call, or nil 50 types []reflect.Type // frame types, used by function literals only 51 scope *scope // frame scope 52 action action // action 53 exec bltn // generated function to execute 54 gen bltnGenerator // generator function to produce above bltn 55 val interface{} // static generic value (CFG execution) 56 rval reflect.Value // reflection value to let runtime access interpreter (CFG) 57 ident string // set if node is a var or func 58 meta interface{} // meta stores meta information between gta runs, like errors 59 } 60 61 func (n *node) shouldBreak() bool { 62 if n == nil || n.debug == nil { 63 return false 64 } 65 66 if n.debug.breakOnLine || n.debug.breakOnCall { 67 return true 68 } 69 70 return false 71 } 72 73 func (n *node) setProgram(p *Program) { 74 if n.debug == nil { 75 n.debug = new(nodeDebugData) 76 } 77 n.debug.program = p 78 } 79 80 func (n *node) setBreakOnCall(v bool) { 81 if n.debug == nil { 82 if !v { 83 return 84 } 85 n.debug = new(nodeDebugData) 86 } 87 n.debug.breakOnCall = v 88 } 89 90 func (n *node) setBreakOnLine(v bool) { 91 if n.debug == nil { 92 if !v { 93 return 94 } 95 n.debug = new(nodeDebugData) 96 } 97 n.debug.breakOnLine = v 98 } 99 100 // receiver stores method receiver object access path. 101 type receiver struct { 102 node *node // receiver value for alias and struct types 103 val reflect.Value // receiver value for interface type and value type 104 index []int // path in receiver value for interface or value type 105 } 106 107 // frame contains values for the current execution level (a function context). 108 type frame struct { 109 // id is an atomic counter used for cancellation, only accessed 110 // via newFrame/runid/setrunid/clone. 111 // Located at start of struct to ensure proper aligment. 112 id uint64 113 114 debug *frameDebugData 115 116 root *frame // global space 117 anc *frame // ancestor frame (caller space) 118 data []reflect.Value // values 119 120 mutex sync.RWMutex 121 deferred [][]reflect.Value // defer stack 122 recovered interface{} // to handle panic recover 123 done reflect.SelectCase // for cancellation of channel operations 124 } 125 126 func newFrame(anc *frame, length int, id uint64) *frame { 127 f := &frame{ 128 anc: anc, 129 data: make([]reflect.Value, length), 130 id: id, 131 } 132 if anc == nil { 133 f.root = f 134 } else { 135 f.done = anc.done 136 f.root = anc.root 137 } 138 return f 139 } 140 141 func (f *frame) runid() uint64 { return atomic.LoadUint64(&f.id) } 142 func (f *frame) setrunid(id uint64) { atomic.StoreUint64(&f.id, id) } 143 func (f *frame) clone(fork bool) *frame { 144 f.mutex.RLock() 145 defer f.mutex.RUnlock() 146 nf := &frame{ 147 anc: f.anc, 148 root: f.root, 149 deferred: f.deferred, 150 recovered: f.recovered, 151 id: f.runid(), 152 done: f.done, 153 debug: f.debug, 154 } 155 if fork { 156 nf.data = make([]reflect.Value, len(f.data)) 157 copy(nf.data, f.data) 158 } else { 159 nf.data = f.data 160 } 161 return nf 162 } 163 164 // Exports stores the map of binary packages per package path. 165 // The package path is the path joined from the import path and the package name 166 // as specified in source files by the "package" statement. 167 type Exports map[string]map[string]reflect.Value 168 169 // imports stores the map of source packages per package path. 170 type imports map[string]map[string]*symbol 171 172 // opt stores interpreter options. 173 type opt struct { 174 // dotCmd is the command to process the dot graph produced when astDot and/or 175 // cfgDot is enabled. It defaults to 'dot -Tdot -o <filename>.dot'. 176 dotCmd string 177 context build.Context // build context: GOPATH, build constraints 178 stdin io.Reader // standard input 179 stdout io.Writer // standard output 180 stderr io.Writer // standard error 181 args []string // cmdline args 182 env map[string]string // environment of interpreter, entries in form of "key=value" 183 filesystem fs.FS // filesystem containing sources 184 astDot bool // display AST graph (debug) 185 cfgDot bool // display CFG graph (debug) 186 noRun bool // compile, but do not run 187 fastChan bool // disable cancellable chan operations 188 specialStdio bool // allows os.Stdin, os.Stdout, os.Stderr to not be file descriptors 189 unrestricted bool // allow use of non sandboxed symbols 190 } 191 192 // Interpreter contains global resources and state. 193 type Interpreter struct { 194 // id is an atomic counter counter used for run cancellation, 195 // only accessed via runid/stop 196 // Located at start of struct to ensure proper alignment on 32 bit 197 // architectures. 198 id uint64 199 200 // nindex is a node number incremented for each new node. 201 // It is used for debug (AST and CFG graphs). As it is atomically 202 // incremented, keep it aligned on 64 bits boundary. 203 nindex int64 204 205 name string // name of the input source file (or main) 206 207 opt // user settable options 208 cancelChan bool // enables cancellable chan operations 209 fset *token.FileSet // fileset to locate node in source code 210 binPkg Exports // binary packages used in interpreter, indexed by path 211 rdir map[string]bool // for src import cycle detection 212 mapTypes map[reflect.Value][]reflect.Type // special interfaces mapping for wrappers 213 214 mutex sync.RWMutex 215 frame *frame // program data storage during execution 216 universe *scope // interpreter global level scope 217 scopes map[string]*scope // package level scopes, indexed by import path 218 srcPkg imports // source packages used in interpreter, indexed by path 219 pkgNames map[string]string // package names, indexed by import path 220 done chan struct{} // for cancellation of channel operations 221 roots []*node 222 223 hooks *hooks // symbol hooks 224 225 debugger *Debugger 226 } 227 228 const ( 229 mainID = "main" 230 selfPrefix = "github.com/traefik/yaegi" 231 selfPath = selfPrefix + "/interp/interp" 232 // DefaultSourceName is the name used by default when the name of the input 233 // source file has not been specified for an Eval. 234 // TODO(mpl): something even more special as a name? 235 DefaultSourceName = "_.go" 236 237 // Test is the value to pass to EvalPath to activate evaluation of test functions. 238 Test = false 239 // NoTest is the value to pass to EvalPath to skip evaluation of test functions. 240 NoTest = true 241 ) 242 243 // Self points to the current interpreter if accessed from within itself, or is nil. 244 var Self *Interpreter 245 246 // Symbols exposes interpreter values. 247 var Symbols = Exports{ 248 selfPath: map[string]reflect.Value{ 249 "New": reflect.ValueOf(New), 250 251 "Interpreter": reflect.ValueOf((*Interpreter)(nil)), 252 "Options": reflect.ValueOf((*Options)(nil)), 253 "Panic": reflect.ValueOf((*Panic)(nil)), 254 }, 255 } 256 257 func init() { Symbols[selfPath]["Symbols"] = reflect.ValueOf(Symbols) } 258 259 // _error is a wrapper of error interface type. 260 type _error struct { 261 IValue interface{} 262 WError func() string 263 } 264 265 func (w _error) Error() string { return w.WError() } 266 267 // Panic is an error recovered from a panic call in interpreted code. 268 type Panic struct { 269 // Value is the recovered value of a call to panic. 270 Value interface{} 271 272 // Callers is the call stack obtained from the recover call. 273 // It may be used as the parameter to runtime.CallersFrames. 274 Callers []uintptr 275 276 // Stack is the call stack buffer for debug. 277 Stack []byte 278 } 279 280 // TODO: Capture interpreter stack frames also and remove 281 // fmt.Fprintln(n.interp.stderr, oNode.cfgErrorf("panic")) in runCfg. 282 283 func (e Panic) Error() string { return fmt.Sprint(e.Value) } 284 285 // Walk traverses AST n in depth first order, call cbin function 286 // at node entry and cbout function at node exit. 287 func (n *node) Walk(in func(n *node) bool, out func(n *node)) { 288 if in != nil && !in(n) { 289 return 290 } 291 for _, child := range n.child { 292 child.Walk(in, out) 293 } 294 if out != nil { 295 out(n) 296 } 297 } 298 299 // Options are the interpreter options. 300 type Options struct { 301 // GoPath sets GOPATH for the interpreter. 302 GoPath string 303 304 // BuildTags sets build constraints for the interpreter. 305 BuildTags []string 306 307 // Standard input, output and error streams. 308 // They default to os.Stdin, os.Stdout and os.Stderr respectively. 309 Stdin io.Reader 310 Stdout, Stderr io.Writer 311 312 // Cmdline args, defaults to os.Args. 313 Args []string 314 315 // Environment of interpreter. Entries are in the form "key=values". 316 Env []string 317 318 // SourcecodeFilesystem is where the _sourcecode_ is loaded from and does 319 // NOT affect the filesystem of scripts when they run. 320 // It can be any fs.FS compliant filesystem (e.g. embed.FS, or fstest.MapFS for testing) 321 // See example/fs/fs_test.go for an example. 322 SourcecodeFilesystem fs.FS 323 324 // Unrestricted allows to run non sandboxed stdlib symbols such as os/exec and environment 325 Unrestricted bool 326 } 327 328 // New returns a new interpreter. 329 func New(options Options) *Interpreter { 330 i := Interpreter{ 331 opt: opt{context: build.Default, filesystem: &realFS{}, env: map[string]string{}}, 332 frame: newFrame(nil, 0, 0), 333 fset: token.NewFileSet(), 334 universe: initUniverse(), 335 scopes: map[string]*scope{}, 336 binPkg: Exports{"": map[string]reflect.Value{"_error": reflect.ValueOf((*_error)(nil))}}, 337 mapTypes: map[reflect.Value][]reflect.Type{}, 338 srcPkg: imports{}, 339 pkgNames: map[string]string{}, 340 rdir: map[string]bool{}, 341 hooks: &hooks{}, 342 } 343 344 if i.opt.stdin = options.Stdin; i.opt.stdin == nil { 345 i.opt.stdin = os.Stdin 346 } 347 348 if i.opt.stdout = options.Stdout; i.opt.stdout == nil { 349 i.opt.stdout = os.Stdout 350 } 351 352 if i.opt.stderr = options.Stderr; i.opt.stderr == nil { 353 i.opt.stderr = os.Stderr 354 } 355 356 if i.opt.args = options.Args; i.opt.args == nil { 357 i.opt.args = os.Args 358 } 359 360 // unrestricted allows to use non sandboxed stdlib symbols and env. 361 if options.Unrestricted { 362 i.opt.unrestricted = true 363 } else { 364 for _, e := range options.Env { 365 a := strings.SplitN(e, "=", 2) 366 if len(a) == 2 { 367 i.opt.env[a[0]] = a[1] 368 } else { 369 i.opt.env[a[0]] = "" 370 } 371 } 372 } 373 374 if options.SourcecodeFilesystem != nil { 375 i.opt.filesystem = options.SourcecodeFilesystem 376 } 377 378 i.opt.context.GOPATH = options.GoPath 379 if len(options.BuildTags) > 0 { 380 i.opt.context.BuildTags = options.BuildTags 381 } 382 383 // astDot activates AST graph display for the interpreter 384 i.opt.astDot, _ = strconv.ParseBool(os.Getenv("YAEGI_AST_DOT")) 385 386 // cfgDot activates CFG graph display for the interpreter 387 i.opt.cfgDot, _ = strconv.ParseBool(os.Getenv("YAEGI_CFG_DOT")) 388 389 // dotCmd defines how to process the dot code generated whenever astDot and/or 390 // cfgDot is enabled. It defaults to 'dot -Tdot -o<filename>.dot' where filename 391 // is context dependent. 392 i.opt.dotCmd = os.Getenv("YAEGI_DOT_CMD") 393 394 // noRun disables the execution (but not the compilation) in the interpreter 395 i.opt.noRun, _ = strconv.ParseBool(os.Getenv("YAEGI_NO_RUN")) 396 397 // fastChan disables the cancellable version of channel operations in evalWithContext 398 i.opt.fastChan, _ = strconv.ParseBool(os.Getenv("YAEGI_FAST_CHAN")) 399 400 // specialStdio allows to assign directly io.Writer and io.Reader to os.Stdxxx, 401 // even if they are not file descriptors. 402 i.opt.specialStdio, _ = strconv.ParseBool(os.Getenv("YAEGI_SPECIAL_STDIO")) 403 404 return &i 405 } 406 407 const ( 408 bltnAppend = "append" 409 bltnCap = "cap" 410 bltnClose = "close" 411 bltnComplex = "complex" 412 bltnImag = "imag" 413 bltnCopy = "copy" 414 bltnDelete = "delete" 415 bltnLen = "len" 416 bltnMake = "make" 417 bltnNew = "new" 418 bltnPanic = "panic" 419 bltnPrint = "print" 420 bltnPrintln = "println" 421 bltnReal = "real" 422 bltnRecover = "recover" 423 ) 424 425 func initUniverse() *scope { 426 sc := &scope{global: true, sym: map[string]*symbol{ 427 // predefined Go types 428 "bool": {kind: typeSym, typ: &itype{cat: boolT, name: "bool", str: "bool"}}, 429 "byte": {kind: typeSym, typ: &itype{cat: uint8T, name: "uint8", str: "uint8"}}, 430 "complex64": {kind: typeSym, typ: &itype{cat: complex64T, name: "complex64", str: "complex64"}}, 431 "complex128": {kind: typeSym, typ: &itype{cat: complex128T, name: "complex128", str: "complex128"}}, 432 "error": {kind: typeSym, typ: &itype{cat: errorT, name: "error", str: "error"}}, 433 "float32": {kind: typeSym, typ: &itype{cat: float32T, name: "float32", str: "float32"}}, 434 "float64": {kind: typeSym, typ: &itype{cat: float64T, name: "float64", str: "float64"}}, 435 "int": {kind: typeSym, typ: &itype{cat: intT, name: "int", str: "int"}}, 436 "int8": {kind: typeSym, typ: &itype{cat: int8T, name: "int8", str: "int8"}}, 437 "int16": {kind: typeSym, typ: &itype{cat: int16T, name: "int16", str: "int16"}}, 438 "int32": {kind: typeSym, typ: &itype{cat: int32T, name: "int32", str: "int32"}}, 439 "int64": {kind: typeSym, typ: &itype{cat: int64T, name: "int64", str: "int64"}}, 440 "interface{}": {kind: typeSym, typ: &itype{cat: interfaceT, str: "interface{}"}}, 441 "rune": {kind: typeSym, typ: &itype{cat: int32T, name: "int32", str: "int32"}}, 442 "string": {kind: typeSym, typ: &itype{cat: stringT, name: "string", str: "string"}}, 443 "uint": {kind: typeSym, typ: &itype{cat: uintT, name: "uint", str: "uint"}}, 444 "uint8": {kind: typeSym, typ: &itype{cat: uint8T, name: "uint8", str: "uint8"}}, 445 "uint16": {kind: typeSym, typ: &itype{cat: uint16T, name: "uint16", str: "uint16"}}, 446 "uint32": {kind: typeSym, typ: &itype{cat: uint32T, name: "uint32", str: "uint32"}}, 447 "uint64": {kind: typeSym, typ: &itype{cat: uint64T, name: "uint64", str: "uint64"}}, 448 "uintptr": {kind: typeSym, typ: &itype{cat: uintptrT, name: "uintptr", str: "uintptr"}}, 449 450 // predefined Go constants 451 "false": {kind: constSym, typ: untypedBool(), rval: reflect.ValueOf(false)}, 452 "true": {kind: constSym, typ: untypedBool(), rval: reflect.ValueOf(true)}, 453 "iota": {kind: constSym, typ: untypedInt()}, 454 455 // predefined Go zero value 456 "nil": {typ: &itype{cat: nilT, untyped: true, str: "nil"}}, 457 458 // predefined Go builtins 459 bltnAppend: {kind: bltnSym, builtin: _append}, 460 bltnCap: {kind: bltnSym, builtin: _cap}, 461 bltnClose: {kind: bltnSym, builtin: _close}, 462 bltnComplex: {kind: bltnSym, builtin: _complex}, 463 bltnImag: {kind: bltnSym, builtin: _imag}, 464 bltnCopy: {kind: bltnSym, builtin: _copy}, 465 bltnDelete: {kind: bltnSym, builtin: _delete}, 466 bltnLen: {kind: bltnSym, builtin: _len}, 467 bltnMake: {kind: bltnSym, builtin: _make}, 468 bltnNew: {kind: bltnSym, builtin: _new}, 469 bltnPanic: {kind: bltnSym, builtin: _panic}, 470 bltnPrint: {kind: bltnSym, builtin: _print}, 471 bltnPrintln: {kind: bltnSym, builtin: _println}, 472 bltnReal: {kind: bltnSym, builtin: _real}, 473 bltnRecover: {kind: bltnSym, builtin: _recover}, 474 }} 475 return sc 476 } 477 478 // resizeFrame resizes the global frame of interpreter. 479 func (interp *Interpreter) resizeFrame() { 480 l := len(interp.universe.types) 481 b := len(interp.frame.data) 482 if l-b <= 0 { 483 return 484 } 485 data := make([]reflect.Value, l) 486 copy(data, interp.frame.data) 487 for j, t := range interp.universe.types[b:] { 488 data[b+j] = reflect.New(t).Elem() 489 } 490 interp.frame.data = data 491 } 492 493 // Eval evaluates Go code represented as a string. Eval returns the last result 494 // computed by the interpreter, and a non nil error in case of failure. 495 func (interp *Interpreter) Eval(src string) (res reflect.Value, err error) { 496 return interp.eval(src, "", true) 497 } 498 499 // EvalPath evaluates Go code located at path and returns the last result computed 500 // by the interpreter, and a non nil error in case of failure. 501 // The main function of the main package is executed if present. 502 func (interp *Interpreter) EvalPath(path string) (res reflect.Value, err error) { 503 if !isFile(interp.opt.filesystem, path) { 504 _, err := interp.importSrc(mainID, path, NoTest) 505 return res, err 506 } 507 508 b, err := fs.ReadFile(interp.filesystem, path) 509 if err != nil { 510 return res, err 511 } 512 return interp.eval(string(b), path, false) 513 } 514 515 // EvalPathWithContext evaluates Go code located at path and returns the last 516 // result computed by the interpreter, and a non nil error in case of failure. 517 // The main function of the main package is executed if present. 518 func (interp *Interpreter) EvalPathWithContext(ctx context.Context, path string) (res reflect.Value, err error) { 519 interp.mutex.Lock() 520 interp.done = make(chan struct{}) 521 interp.cancelChan = !interp.opt.fastChan 522 interp.mutex.Unlock() 523 524 done := make(chan struct{}) 525 go func() { 526 defer close(done) 527 res, err = interp.EvalPath(path) 528 }() 529 530 select { 531 case <-ctx.Done(): 532 interp.stop() 533 return reflect.Value{}, ctx.Err() 534 case <-done: 535 } 536 return res, err 537 } 538 539 // EvalTest evaluates Go code located at path, including test files with "_test.go" suffix. 540 // A non nil error is returned in case of failure. 541 // The main function, test functions and benchmark functions are internally compiled but not 542 // executed. Test functions can be retrieved using the Symbol() method. 543 func (interp *Interpreter) EvalTest(path string) error { 544 _, err := interp.importSrc(mainID, path, Test) 545 return err 546 } 547 548 // Symbols returns a map of interpreter exported symbol values for the given 549 // import path. If the argument is the empty string, all known symbols are 550 // returned. 551 func (interp *Interpreter) Symbols(importPath string) Exports { 552 m := map[string]map[string]reflect.Value{} 553 interp.mutex.RLock() 554 defer interp.mutex.RUnlock() 555 556 for k, v := range interp.srcPkg { 557 if importPath != "" && k != importPath { 558 continue 559 } 560 syms := map[string]reflect.Value{} 561 for n, s := range v { 562 if !canExport(n) { 563 // Skip private non-exported symbols. 564 continue 565 } 566 switch s.kind { 567 case constSym: 568 syms[n] = s.rval 569 case funcSym: 570 syms[n] = genFunctionWrapper(s.node)(interp.frame) 571 case varSym: 572 syms[n] = interp.frame.data[s.index] 573 case typeSym: 574 syms[n] = reflect.New(s.typ.TypeOf()) 575 } 576 } 577 578 if len(syms) > 0 { 579 m[k] = syms 580 } 581 582 if importPath != "" { 583 return m 584 } 585 } 586 587 if importPath != "" && len(m) > 0 { 588 return m 589 } 590 591 for k, v := range interp.binPkg { 592 if importPath != "" && k != importPath { 593 continue 594 } 595 m[k] = v 596 if importPath != "" { 597 return m 598 } 599 } 600 601 return m 602 } 603 604 func isFile(filesystem fs.FS, path string) bool { 605 fi, err := fs.Stat(filesystem, path) 606 return err == nil && fi.Mode().IsRegular() 607 } 608 609 func (interp *Interpreter) eval(src, name string, inc bool) (res reflect.Value, err error) { 610 prog, err := interp.compileSrc(src, name, inc) 611 if err != nil { 612 return res, err 613 } 614 615 if interp.noRun { 616 return res, err 617 } 618 619 return interp.Execute(prog) 620 } 621 622 // EvalWithContext evaluates Go code represented as a string. It returns 623 // a map on current interpreted package exported symbols. 624 func (interp *Interpreter) EvalWithContext(ctx context.Context, src string) (reflect.Value, error) { 625 var v reflect.Value 626 var err error 627 628 interp.mutex.Lock() 629 interp.done = make(chan struct{}) 630 interp.cancelChan = !interp.opt.fastChan 631 interp.mutex.Unlock() 632 633 done := make(chan struct{}) 634 go func() { 635 defer func() { 636 if r := recover(); r != nil { 637 var pc [64]uintptr 638 n := runtime.Callers(1, pc[:]) 639 err = Panic{Value: r, Callers: pc[:n], Stack: debug.Stack()} 640 } 641 close(done) 642 }() 643 v, err = interp.Eval(src) 644 }() 645 646 select { 647 case <-ctx.Done(): 648 interp.stop() 649 return reflect.Value{}, ctx.Err() 650 case <-done: 651 } 652 return v, err 653 } 654 655 // stop sends a semaphore to all running frames and closes the chan 656 // operation short circuit channel. stop may only be called once per 657 // invocation of EvalWithContext. 658 func (interp *Interpreter) stop() { 659 atomic.AddUint64(&interp.id, 1) 660 close(interp.done) 661 } 662 663 func (interp *Interpreter) runid() uint64 { return atomic.LoadUint64(&interp.id) } 664 665 // getWrapper returns the wrapper type of the corresponding interface, or nil if not found. 666 func (interp *Interpreter) getWrapper(t reflect.Type) reflect.Type { 667 if p, ok := interp.binPkg[t.PkgPath()]; ok { 668 return p["_"+t.Name()].Type().Elem() 669 } 670 return nil 671 } 672 673 // Use loads binary runtime symbols in the interpreter context so 674 // they can be used in interpreted code. 675 func (interp *Interpreter) Use(values Exports) error { 676 for k, v := range values { 677 importPath := path.Dir(k) 678 packageName := path.Base(k) 679 680 if k == "." && v["MapTypes"].IsValid() { 681 // Use mapping for special interface wrappers. 682 for kk, vv := range v["MapTypes"].Interface().(map[reflect.Value][]reflect.Type) { 683 interp.mapTypes[kk] = vv 684 } 685 continue 686 } 687 688 if importPath == "." { 689 return fmt.Errorf("export path %[1]q is missing a package name; did you mean '%[1]s/%[1]s'?", k) 690 } 691 692 if importPath == selfPrefix { 693 interp.hooks.Parse(v) 694 continue 695 } 696 697 if interp.binPkg[importPath] == nil { 698 interp.binPkg[importPath] = make(map[string]reflect.Value) 699 interp.pkgNames[importPath] = packageName 700 } 701 702 for s, sym := range v { 703 interp.binPkg[importPath][s] = sym 704 } 705 if k == selfPath { 706 interp.binPkg[importPath]["Self"] = reflect.ValueOf(interp) 707 } 708 } 709 710 // Checks if input values correspond to stdlib packages by looking for one 711 // well known stdlib package path. 712 if _, ok := values["fmt/fmt"]; ok { 713 fixStdlib(interp) 714 } 715 return nil 716 } 717 718 // fixStdlib redefines interpreter stdlib symbols to use the standard input, 719 // output and errror assigned to the interpreter. The changes are limited to 720 // the interpreter only. 721 // Note that it is possible to escape the virtualized stdio by 722 // read/write directly to file descriptors 0, 1, 2. 723 func fixStdlib(interp *Interpreter) { 724 p := interp.binPkg["fmt"] 725 if p == nil { 726 return 727 } 728 729 stdin, stdout, stderr := interp.stdin, interp.stdout, interp.stderr 730 731 p["Print"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fprint(stdout, a...) }) 732 p["Printf"] = reflect.ValueOf(func(f string, a ...interface{}) (n int, err error) { return fmt.Fprintf(stdout, f, a...) }) 733 p["Println"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fprintln(stdout, a...) }) 734 735 p["Scan"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fscan(stdin, a...) }) 736 p["Scanf"] = reflect.ValueOf(func(f string, a ...interface{}) (n int, err error) { return fmt.Fscanf(stdin, f, a...) }) 737 p["Scanln"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fscanln(stdin, a...) }) 738 739 // Update mapTypes to virtualized symbols as well. 740 interp.mapTypes[p["Print"]] = interp.mapTypes[reflect.ValueOf(fmt.Print)] 741 interp.mapTypes[p["Printf"]] = interp.mapTypes[reflect.ValueOf(fmt.Printf)] 742 interp.mapTypes[p["Println"]] = interp.mapTypes[reflect.ValueOf(fmt.Println)] 743 interp.mapTypes[p["Scan"]] = interp.mapTypes[reflect.ValueOf(fmt.Scan)] 744 interp.mapTypes[p["Scanf"]] = interp.mapTypes[reflect.ValueOf(fmt.Scanf)] 745 interp.mapTypes[p["Scanln"]] = interp.mapTypes[reflect.ValueOf(fmt.Scanln)] 746 747 if p = interp.binPkg["flag"]; p != nil { 748 c := flag.NewFlagSet(os.Args[0], flag.PanicOnError) 749 c.SetOutput(stderr) 750 p["CommandLine"] = reflect.ValueOf(&c).Elem() 751 } 752 753 if p = interp.binPkg["log"]; p != nil { 754 l := log.New(stderr, "", log.LstdFlags) 755 // Restrict Fatal symbols to panic instead of exit. 756 p["Fatal"] = reflect.ValueOf(l.Panic) 757 p["Fatalf"] = reflect.ValueOf(l.Panicf) 758 p["Fatalln"] = reflect.ValueOf(l.Panicln) 759 760 p["Flags"] = reflect.ValueOf(l.Flags) 761 p["Output"] = reflect.ValueOf(l.Output) 762 p["Panic"] = reflect.ValueOf(l.Panic) 763 p["Panicf"] = reflect.ValueOf(l.Panicf) 764 p["Panicln"] = reflect.ValueOf(l.Panicln) 765 p["Prefix"] = reflect.ValueOf(l.Prefix) 766 p["Print"] = reflect.ValueOf(l.Print) 767 p["Printf"] = reflect.ValueOf(l.Printf) 768 p["Println"] = reflect.ValueOf(l.Println) 769 p["SetFlags"] = reflect.ValueOf(l.SetFlags) 770 p["SetOutput"] = reflect.ValueOf(l.SetOutput) 771 p["SetPrefix"] = reflect.ValueOf(l.SetPrefix) 772 p["Writer"] = reflect.ValueOf(l.Writer) 773 774 // Update mapTypes to virtualized symbols as well. 775 interp.mapTypes[p["Print"]] = interp.mapTypes[reflect.ValueOf(log.Print)] 776 interp.mapTypes[p["Printf"]] = interp.mapTypes[reflect.ValueOf(log.Printf)] 777 interp.mapTypes[p["Println"]] = interp.mapTypes[reflect.ValueOf(log.Println)] 778 interp.mapTypes[p["Panic"]] = interp.mapTypes[reflect.ValueOf(log.Panic)] 779 interp.mapTypes[p["Panicf"]] = interp.mapTypes[reflect.ValueOf(log.Panicf)] 780 interp.mapTypes[p["Panicln"]] = interp.mapTypes[reflect.ValueOf(log.Panicln)] 781 } 782 783 if p = interp.binPkg["os"]; p != nil { 784 p["Args"] = reflect.ValueOf(&interp.args).Elem() 785 if interp.specialStdio { 786 // Inherit streams from interpreter even if they do not have a file descriptor. 787 p["Stdin"] = reflect.ValueOf(&stdin).Elem() 788 p["Stdout"] = reflect.ValueOf(&stdout).Elem() 789 p["Stderr"] = reflect.ValueOf(&stderr).Elem() 790 } else { 791 // Inherits streams from interpreter only if they have a file descriptor and preserve original type. 792 if s, ok := stdin.(*os.File); ok { 793 p["Stdin"] = reflect.ValueOf(&s).Elem() 794 } 795 if s, ok := stdout.(*os.File); ok { 796 p["Stdout"] = reflect.ValueOf(&s).Elem() 797 } 798 if s, ok := stderr.(*os.File); ok { 799 p["Stderr"] = reflect.ValueOf(&s).Elem() 800 } 801 } 802 if !interp.unrestricted { 803 // In restricted mode, scripts can only access to a passed virtualized env, and can not write the real one. 804 getenv := func(key string) string { return interp.env[key] } 805 p["Clearenv"] = reflect.ValueOf(func() { interp.env = map[string]string{} }) 806 p["ExpandEnv"] = reflect.ValueOf(func(s string) string { return os.Expand(s, getenv) }) 807 p["Getenv"] = reflect.ValueOf(getenv) 808 p["LookupEnv"] = reflect.ValueOf(func(key string) (s string, ok bool) { s, ok = interp.env[key]; return }) 809 p["Setenv"] = reflect.ValueOf(func(key, value string) error { interp.env[key] = value; return nil }) 810 p["Unsetenv"] = reflect.ValueOf(func(key string) error { delete(interp.env, key); return nil }) 811 p["Environ"] = reflect.ValueOf(func() (a []string) { 812 for k, v := range interp.env { 813 a = append(a, k+"="+v) 814 } 815 return 816 }) 817 } 818 } 819 820 if p = interp.binPkg["math/bits"]; p != nil { 821 // Do not trust extracted value maybe from another arch. 822 p["UintSize"] = reflect.ValueOf(constant.MakeInt64(bits.UintSize)) 823 } 824 } 825 826 // ignoreScannerError returns true if the error from Go scanner can be safely ignored 827 // to let the caller grab one more line before retrying to parse its input. 828 func ignoreScannerError(e *scanner.Error, s string) bool { 829 msg := e.Msg 830 if strings.HasSuffix(msg, "found 'EOF'") { 831 return true 832 } 833 if msg == "raw string literal not terminated" { 834 return true 835 } 836 if strings.HasPrefix(msg, "expected operand, found '}'") && !strings.HasSuffix(s, "}") { 837 return true 838 } 839 return false 840 } 841 842 // ImportUsed automatically imports pre-compiled packages included by Use(). 843 // This is mainly useful for REPLs, or single command lines. In case of an ambiguous default 844 // package name, for example "rand" for crypto/rand and math/rand, the package name is 845 // constructed by replacing the last "/" by a "_", producing crypto_rand and math_rand. 846 // ImportUsed should not be called more than once, and not after a first Eval, as it may 847 // rename packages. 848 func (interp *Interpreter) ImportUsed() { 849 sc := interp.universe 850 for k := range interp.binPkg { 851 // By construction, the package name is the last path element of the key. 852 name := path.Base(k) 853 if sym, ok := sc.sym[name]; ok { 854 // Handle collision by renaming old and new entries. 855 name2 := key2name(fixKey(sym.typ.path)) 856 sc.sym[name2] = sym 857 if name2 != name { 858 delete(sc.sym, name) 859 } 860 name = key2name(fixKey(k)) 861 } 862 sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: k, scope: sc}} 863 } 864 } 865 866 func key2name(name string) string { 867 return filepath.Join(name, DefaultSourceName) 868 } 869 870 func fixKey(k string) string { 871 i := strings.LastIndex(k, "/") 872 if i >= 0 { 873 k = k[:i] + "_" + k[i+1:] 874 } 875 return k 876 } 877 878 // REPL performs a Read-Eval-Print-Loop on input reader. 879 // Results are printed to the output writer of the Interpreter, provided as option 880 // at creation time. Errors are printed to the similarly defined errors writer. 881 // The last interpreter result value and error are returned. 882 func (interp *Interpreter) REPL() (reflect.Value, error) { 883 in, out, errs := interp.stdin, interp.stdout, interp.stderr 884 ctx, cancel := context.WithCancel(context.Background()) 885 end := make(chan struct{}) // channel to terminate the REPL 886 sig := make(chan os.Signal, 1) // channel to trap interrupt signal (Ctrl-C) 887 lines := make(chan string) // channel to read REPL input lines 888 prompt := getPrompt(in, out) // prompt activated on tty like IO stream 889 s := bufio.NewScanner(in) // read input stream line by line 890 var v reflect.Value // result value from eval 891 var err error // error from eval 892 src := "" // source string to evaluate 893 894 signal.Notify(sig, os.Interrupt) 895 defer signal.Stop(sig) 896 prompt(v) 897 898 go func() { 899 defer close(end) 900 for s.Scan() { 901 lines <- s.Text() 902 } 903 if e := s.Err(); e != nil { 904 fmt.Fprintln(errs, e) 905 } 906 }() 907 908 go func() { 909 for { 910 select { 911 case <-sig: 912 cancel() 913 lines <- "" 914 case <-end: 915 return 916 } 917 } 918 }() 919 920 for { 921 var line string 922 923 select { 924 case <-end: 925 cancel() 926 return v, err 927 case line = <-lines: 928 src += line + "\n" 929 } 930 931 v, err = interp.EvalWithContext(ctx, src) 932 if err != nil { 933 switch e := err.(type) { 934 case scanner.ErrorList: 935 if len(e) > 0 && ignoreScannerError(e[0], line) { 936 continue 937 } 938 fmt.Fprintln(errs, strings.TrimPrefix(e[0].Error(), DefaultSourceName+":")) 939 case Panic: 940 fmt.Fprintln(errs, e.Value) 941 fmt.Fprintln(errs, string(e.Stack)) 942 default: 943 fmt.Fprintln(errs, err) 944 } 945 } 946 if errors.Is(err, context.Canceled) { 947 ctx, cancel = context.WithCancel(context.Background()) 948 } 949 src = "" 950 prompt(v) 951 } 952 } 953 954 func doPrompt(out io.Writer) func(v reflect.Value) { 955 return func(v reflect.Value) { 956 if v.IsValid() { 957 fmt.Fprintln(out, ":", v) 958 } 959 fmt.Fprint(out, "> ") 960 } 961 } 962 963 // getPrompt returns a function which prints a prompt only if input is a terminal. 964 func getPrompt(in io.Reader, out io.Writer) func(reflect.Value) { 965 forcePrompt, _ := strconv.ParseBool(os.Getenv("YAEGI_PROMPT")) 966 if forcePrompt { 967 return doPrompt(out) 968 } 969 s, ok := in.(interface{ Stat() (os.FileInfo, error) }) 970 if !ok { 971 return func(reflect.Value) {} 972 } 973 stat, err := s.Stat() 974 if err == nil && stat.Mode()&os.ModeCharDevice != 0 { 975 return doPrompt(out) 976 } 977 return func(reflect.Value) {} 978 }