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