github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/compile_value.go (about)

     1  package eval
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/u-root/u-root/cmds/core/elvish/eval/vals"
    14  	"github.com/u-root/u-root/cmds/core/elvish/glob"
    15  	"github.com/u-root/u-root/cmds/core/elvish/parse"
    16  	"github.com/u-root/u-root/cmds/core/elvish/util"
    17  )
    18  
    19  var outputCaptureBufferSize = 16
    20  
    21  // ValuesOp is an operation on an Frame that produce Value's.
    22  type ValuesOp struct {
    23  	Body       ValuesOpBody
    24  	Begin, End int
    25  }
    26  
    27  // ValuesOpBody is the body of ValuesOp.
    28  type ValuesOpBody interface {
    29  	Invoke(*Frame) ([]interface{}, error)
    30  }
    31  
    32  // Exec executes a ValuesOp and produces Value's.
    33  func (op ValuesOp) Exec(fm *Frame) ([]interface{}, error) {
    34  	fm.begin, fm.end = op.Begin, op.End
    35  	return op.Body.Invoke(fm)
    36  }
    37  
    38  func (cp *compiler) compound(n *parse.Compound) ValuesOpBody {
    39  	if len(n.Indexings) == 0 {
    40  		return literalStr("")
    41  	}
    42  
    43  	tilde := false
    44  	indexings := n.Indexings
    45  
    46  	if n.Indexings[0].Head.Type == parse.Tilde {
    47  		// A lone ~.
    48  		if len(n.Indexings) == 1 {
    49  			return funcValuesOp(func(fm *Frame) ([]interface{}, error) {
    50  				home, err := util.GetHome("")
    51  				if err != nil {
    52  					return nil, err
    53  				}
    54  				return []interface{}{home}, nil
    55  			})
    56  		}
    57  		tilde = true
    58  		indexings = indexings[1:]
    59  	}
    60  
    61  	return compoundOp{tilde, cp.indexingOps(indexings)}
    62  }
    63  
    64  type compoundOp struct {
    65  	tilde  bool
    66  	subops []ValuesOp
    67  }
    68  
    69  func (op compoundOp) Invoke(fm *Frame) ([]interface{}, error) {
    70  	// Accumulator.
    71  	vs, err := op.subops[0].Exec(fm)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	for _, subop := range op.subops[1:] {
    77  		us, err := subop.Exec(fm)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  		vs, err = outerProduct(vs, us, vals.Concat)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  	}
    86  	if op.tilde {
    87  		newvs := make([]interface{}, len(vs))
    88  		for i, v := range vs {
    89  			newvs[i] = doTilde(v)
    90  		}
    91  		vs = newvs
    92  	}
    93  	hasGlob := false
    94  	for _, v := range vs {
    95  		if _, ok := v.(GlobPattern); ok {
    96  			hasGlob = true
    97  			break
    98  		}
    99  	}
   100  	if hasGlob {
   101  		newvs := make([]interface{}, 0, len(vs))
   102  		for _, v := range vs {
   103  			if gp, ok := v.(GlobPattern); ok {
   104  				// Logger.Printf("globbing %v", gp)
   105  				newvs = append(newvs, doGlob(gp, fm.Interrupts())...)
   106  			} else {
   107  				newvs = append(newvs, v)
   108  			}
   109  		}
   110  		vs = newvs
   111  	}
   112  	return vs, nil
   113  }
   114  
   115  func outerProduct(vs []interface{}, us []interface{}, f func(interface{}, interface{}) (interface{}, error)) ([]interface{}, error) {
   116  	ws := make([]interface{}, len(vs)*len(us))
   117  	nu := len(us)
   118  	for i, v := range vs {
   119  		for j, u := range us {
   120  			var err error
   121  			ws[i*nu+j], err = f(v, u)
   122  			if err != nil {
   123  				return nil, err
   124  			}
   125  		}
   126  	}
   127  	return ws, nil
   128  }
   129  
   130  // Errors thrown when globbing.
   131  var (
   132  	ErrBadGlobPattern          = errors.New("bad GlobPattern; elvish bug")
   133  	ErrCannotDetermineUsername = errors.New("cannot determine user name from glob pattern")
   134  )
   135  
   136  func doTilde(v interface{}) interface{} {
   137  	switch v := v.(type) {
   138  	case string:
   139  		s := v
   140  		i := strings.Index(s, "/")
   141  		var uname, rest string
   142  		if i == -1 {
   143  			uname = s
   144  		} else {
   145  			uname = s[:i]
   146  			rest = s[i+1:]
   147  		}
   148  		dir := mustGetHome(uname)
   149  		return path.Join(dir, rest)
   150  	case GlobPattern:
   151  		if len(v.Segments) == 0 {
   152  			throw(ErrBadGlobPattern)
   153  		}
   154  		switch seg := v.Segments[0].(type) {
   155  		case glob.Literal:
   156  			s := seg.Data
   157  			// Find / in the first segment to determine the username.
   158  			i := strings.Index(s, "/")
   159  			if i == -1 {
   160  				throw(ErrCannotDetermineUsername)
   161  			}
   162  			uname := s[:i]
   163  			dir := mustGetHome(uname)
   164  			// Replace ~uname in first segment with the found path.
   165  			v.Segments[0] = glob.Literal{dir + s[i:]}
   166  		case glob.Slash:
   167  			v.DirOverride = mustGetHome("")
   168  		default:
   169  			throw(ErrCannotDetermineUsername)
   170  		}
   171  		return v
   172  	default:
   173  		throw(fmt.Errorf("tilde doesn't work on value of type %s", vals.Kind(v)))
   174  		panic("unreachable")
   175  	}
   176  }
   177  
   178  func (cp *compiler) array(n *parse.Array) ValuesOpBody {
   179  	return seqValuesOp{cp.compoundOps(n.Compounds)}
   180  }
   181  
   182  func (cp *compiler) indexing(n *parse.Indexing) ValuesOpBody {
   183  	if len(n.Indicies) == 0 {
   184  		return cp.primary(n.Head)
   185  	}
   186  
   187  	return &indexingOp{cp.primaryOp(n.Head), cp.arrayOps(n.Indicies)}
   188  }
   189  
   190  type indexingOp struct {
   191  	headOp   ValuesOp
   192  	indexOps []ValuesOp
   193  }
   194  
   195  func (op *indexingOp) Invoke(fm *Frame) ([]interface{}, error) {
   196  	vs, err := op.headOp.Exec(fm)
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	for _, indexOp := range op.indexOps {
   201  		indicies, err := indexOp.Exec(fm)
   202  		if err != nil {
   203  			return nil, err
   204  		}
   205  		newvs := make([]interface{}, 0, len(vs)*len(indicies))
   206  		for _, v := range vs {
   207  			for _, index := range indicies {
   208  				result, err := vals.Index(v, index)
   209  				if err != nil {
   210  					return nil, err
   211  				}
   212  				newvs = append(newvs, result)
   213  			}
   214  		}
   215  		vs = newvs
   216  	}
   217  	return vs, nil
   218  }
   219  
   220  func (cp *compiler) primary(n *parse.Primary) ValuesOpBody {
   221  	switch n.Type {
   222  	case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
   223  		return literalStr(n.Value)
   224  	case parse.Variable:
   225  		explode, ns, name := ParseVariableRef(n.Value)
   226  		if !cp.registerVariableGet(ns, name) {
   227  			cp.errorf("variable $%s not found", n.Value)
   228  		}
   229  		return &variableOp{explode, ns, name}
   230  	case parse.Wildcard:
   231  		seg, err := wildcardToSegment(n.SourceText())
   232  		if err != nil {
   233  			cp.errorf("%s", err)
   234  		}
   235  		vs := []interface{}{
   236  			GlobPattern{glob.Pattern{[]glob.Segment{seg}, ""}, 0, nil}}
   237  		return literalValues(vs...)
   238  	case parse.Tilde:
   239  		cp.errorf("compiler bug: Tilde not handled in .compound")
   240  		return literalStr("~")
   241  	case parse.ExceptionCapture:
   242  		return exceptionCaptureOp{cp.chunkOp(n.Chunk)}
   243  	case parse.OutputCapture:
   244  		return outputCaptureOp{cp.chunkOp(n.Chunk)}
   245  	case parse.List:
   246  		return cp.list(n)
   247  	case parse.Lambda:
   248  		return cp.lambda(n)
   249  	case parse.Map:
   250  		return cp.map_(n)
   251  	case parse.Braced:
   252  		return cp.braced(n)
   253  	default:
   254  		cp.errorf("bad PrimaryType; parser bug")
   255  		return literalStr(n.SourceText())
   256  	}
   257  }
   258  
   259  type variableOp struct {
   260  	explode bool
   261  	ns      string
   262  	name    string
   263  }
   264  
   265  func (op variableOp) Invoke(fm *Frame) ([]interface{}, error) {
   266  	variable := fm.ResolveVar(op.ns, op.name)
   267  	if variable == nil {
   268  		return nil, fmt.Errorf("variable $%s:%s not found", op.ns, op.name)
   269  	}
   270  	value := variable.Get()
   271  	if op.explode {
   272  		return vals.Collect(value)
   273  	}
   274  	return []interface{}{value}, nil
   275  }
   276  
   277  func (cp *compiler) list(n *parse.Primary) ValuesOpBody {
   278  	return listOp{cp.compoundOps(n.Elements)}
   279  }
   280  
   281  type listOp struct{ subops []ValuesOp }
   282  
   283  func (op listOp) Invoke(fm *Frame) ([]interface{}, error) {
   284  	list := vals.EmptyList
   285  	for _, subop := range op.subops {
   286  		moreValues, err := subop.Exec(fm)
   287  		if err != nil {
   288  			return nil, err
   289  		}
   290  		for _, moreValue := range moreValues {
   291  			list = list.Cons(moreValue)
   292  		}
   293  	}
   294  	return []interface{}{list}, nil
   295  }
   296  
   297  type exceptionCaptureOp struct{ subop Op }
   298  
   299  func (op exceptionCaptureOp) Invoke(fm *Frame) ([]interface{}, error) {
   300  	err := fm.Eval(op.subop)
   301  	if err == nil {
   302  		return []interface{}{OK}, nil
   303  	}
   304  	return []interface{}{err.(*Exception)}, nil
   305  }
   306  
   307  type outputCaptureOp struct{ subop Op }
   308  
   309  func (op outputCaptureOp) Invoke(fm *Frame) ([]interface{}, error) {
   310  	return pcaptureOutput(fm, op.subop)
   311  }
   312  
   313  func pcaptureOutput(fm *Frame, op Op) ([]interface{}, error) {
   314  	vs := []interface{}{}
   315  	var m sync.Mutex
   316  	valueCb := func(ch <-chan interface{}) {
   317  		for v := range ch {
   318  			m.Lock()
   319  			vs = append(vs, v)
   320  			m.Unlock()
   321  		}
   322  	}
   323  	bytesCb := func(r *os.File) {
   324  		buffered := bufio.NewReader(r)
   325  		for {
   326  			line, err := buffered.ReadString('\n')
   327  			if line != "" {
   328  				v := strings.TrimSuffix(line, "\n")
   329  				m.Lock()
   330  				vs = append(vs, v)
   331  				m.Unlock()
   332  			}
   333  			if err != nil {
   334  				if err != io.EOF {
   335  					logger.Println("error on reading:", err)
   336  				}
   337  				break
   338  			}
   339  		}
   340  	}
   341  
   342  	err := pcaptureOutputInner(fm, op, valueCb, bytesCb)
   343  	return vs, err
   344  }
   345  
   346  func pcaptureOutputInner(fm *Frame, op Op, valuesCb func(<-chan interface{}), bytesCb func(*os.File)) error {
   347  
   348  	newFm := fm.fork("[output capture]")
   349  
   350  	ch := make(chan interface{}, outputCaptureBufferSize)
   351  	pipeRead, pipeWrite, err := os.Pipe()
   352  	if err != nil {
   353  		return fmt.Errorf("failed to create pipe: %v", err)
   354  	}
   355  	newFm.ports[1] = &Port{
   356  		Chan: ch, CloseChan: true,
   357  		File: pipeWrite, CloseFile: true,
   358  	}
   359  
   360  	bytesCollected := make(chan struct{})
   361  	chCollected := make(chan struct{})
   362  
   363  	go func() {
   364  		valuesCb(ch)
   365  		close(chCollected)
   366  	}()
   367  	go func() {
   368  		bytesCb(pipeRead)
   369  		pipeRead.Close()
   370  		close(bytesCollected)
   371  	}()
   372  
   373  	err = newFm.Eval(op)
   374  
   375  	newFm.Close()
   376  	<-bytesCollected
   377  	<-chCollected
   378  
   379  	return err
   380  }
   381  
   382  func (cp *compiler) lambda(n *parse.Primary) ValuesOpBody {
   383  	// Parse signature.
   384  	var (
   385  		argNames      []string
   386  		restArgName   string
   387  		optNames      []string
   388  		optDefaultOps []ValuesOp
   389  	)
   390  	if len(n.Elements) > 0 {
   391  		// Argument list.
   392  		argNames = make([]string, len(n.Elements))
   393  		for i, arg := range n.Elements {
   394  			qname := mustString(cp, arg, "argument name must be literal string")
   395  			explode, ns, name := ParseVariableRef(qname)
   396  			if ns != "" {
   397  				cp.errorpf(arg.Begin(), arg.End(), "argument name must be unqualified")
   398  			}
   399  			if name == "" {
   400  				cp.errorpf(arg.Begin(), arg.End(), "argument name must not be empty")
   401  			}
   402  			if explode {
   403  				if i != len(n.Elements)-1 {
   404  					cp.errorpf(arg.Begin(), arg.End(), "only the last argument may have @")
   405  				}
   406  				restArgName = name
   407  				argNames = argNames[:i]
   408  			} else {
   409  				argNames[i] = name
   410  			}
   411  		}
   412  	}
   413  	if len(n.MapPairs) > 0 {
   414  		optNames = make([]string, len(n.MapPairs))
   415  		optDefaultOps = make([]ValuesOp, len(n.MapPairs))
   416  		for i, opt := range n.MapPairs {
   417  			qname := mustString(cp, opt.Key, "option name must be literal string")
   418  			_, ns, name := ParseVariableRef(qname)
   419  			if ns != "" {
   420  				cp.errorpf(opt.Key.Begin(), opt.Key.End(), "option name must be unqualified")
   421  			}
   422  			if name == "" {
   423  				cp.errorpf(opt.Key.Begin(), opt.Key.End(), "option name must not be empty")
   424  			}
   425  			optNames[i] = name
   426  			if opt.Value == nil {
   427  				cp.errorpf(opt.End(), opt.End(), "option must have default value")
   428  			} else {
   429  				optDefaultOps[i] = cp.compoundOp(opt.Value)
   430  			}
   431  		}
   432  	}
   433  
   434  	thisScope := cp.pushScope()
   435  	for _, argName := range argNames {
   436  		thisScope.set(argName)
   437  	}
   438  	if restArgName != "" {
   439  		thisScope.set(restArgName)
   440  	}
   441  	for _, optName := range optNames {
   442  		thisScope.set(optName)
   443  	}
   444  
   445  	subop := cp.chunkOp(n.Chunk)
   446  
   447  	// XXX The fiddlings with cp.capture is error-prone.
   448  	capture := cp.capture
   449  	cp.capture = make(staticNs)
   450  	cp.popScope()
   451  
   452  	for name := range capture {
   453  		cp.registerVariableGetQname(name)
   454  	}
   455  
   456  	return &lambdaOp{argNames, restArgName, optNames, optDefaultOps, capture, subop, cp.srcMeta, n.Begin(), n.End()}
   457  }
   458  
   459  type lambdaOp struct {
   460  	argNames      []string
   461  	restArgName   string
   462  	optNames      []string
   463  	optDefaultOps []ValuesOp
   464  	capture       staticNs
   465  	subop         Op
   466  	srcMeta       *Source
   467  	defBegin      int
   468  	defEnd        int
   469  }
   470  
   471  func (op *lambdaOp) Invoke(fm *Frame) ([]interface{}, error) {
   472  	evCapture := make(Ns)
   473  	for name := range op.capture {
   474  		evCapture[name] = fm.ResolveVar("", name)
   475  	}
   476  	optDefaults := make([]interface{}, len(op.optDefaultOps))
   477  	for i, op := range op.optDefaultOps {
   478  		defaultValue := fm.ExecAndUnwrap("option default value", op).One().Any()
   479  		optDefaults[i] = defaultValue
   480  	}
   481  	// XXX(xiaq): Capture uses.
   482  	return []interface{}{&Closure{op.argNames, op.restArgName, op.optNames, optDefaults, op.subop, evCapture, op.srcMeta, op.defBegin, op.defEnd}}, nil
   483  }
   484  
   485  func (cp *compiler) map_(n *parse.Primary) ValuesOpBody {
   486  	return cp.mapPairs(n.MapPairs)
   487  }
   488  
   489  func (cp *compiler) mapPairs(pairs []*parse.MapPair) ValuesOpBody {
   490  	npairs := len(pairs)
   491  	keysOps := make([]ValuesOp, npairs)
   492  	valuesOps := make([]ValuesOp, npairs)
   493  	begins, ends := make([]int, npairs), make([]int, npairs)
   494  	for i, pair := range pairs {
   495  		keysOps[i] = cp.compoundOp(pair.Key)
   496  		if pair.Value == nil {
   497  			p := pair.End()
   498  			valuesOps[i] = ValuesOp{literalValues(true), p, p}
   499  		} else {
   500  			valuesOps[i] = cp.compoundOp(pairs[i].Value)
   501  		}
   502  		begins[i], ends[i] = pair.Begin(), pair.End()
   503  	}
   504  	return &mapPairsOp{keysOps, valuesOps, begins, ends}
   505  }
   506  
   507  type mapPairsOp struct {
   508  	keysOps   []ValuesOp
   509  	valuesOps []ValuesOp
   510  	begins    []int
   511  	ends      []int
   512  }
   513  
   514  func (op *mapPairsOp) Invoke(fm *Frame) ([]interface{}, error) {
   515  	m := vals.EmptyMap
   516  	for i := range op.keysOps {
   517  		keys, err := op.keysOps[i].Exec(fm)
   518  		if err != nil {
   519  			return nil, err
   520  		}
   521  		values, err := op.valuesOps[i].Exec(fm)
   522  		if err != nil {
   523  			return nil, err
   524  		}
   525  		if len(keys) != len(values) {
   526  			fm.errorpf(op.begins[i], op.ends[i],
   527  				"%d keys but %d values", len(keys), len(values))
   528  		}
   529  		for j, key := range keys {
   530  			m = m.Assoc(key, values[j])
   531  		}
   532  	}
   533  	return []interface{}{m}, nil
   534  }
   535  
   536  func (cp *compiler) braced(n *parse.Primary) ValuesOpBody {
   537  	ops := cp.compoundOps(n.Braced)
   538  	// TODO: n.IsRange
   539  	// isRange := n.IsRange
   540  	return seqValuesOp{ops}
   541  }
   542  
   543  type literalValuesOp struct{ values []interface{} }
   544  
   545  func (op literalValuesOp) Invoke(*Frame) ([]interface{}, error) {
   546  	return op.values, nil
   547  }
   548  
   549  func literalValues(v ...interface{}) ValuesOpBody {
   550  	return literalValuesOp{v}
   551  }
   552  
   553  func literalStr(text string) ValuesOpBody {
   554  	return literalValues(text)
   555  }
   556  
   557  type seqValuesOp struct{ subops []ValuesOp }
   558  
   559  func (op seqValuesOp) Invoke(fm *Frame) ([]interface{}, error) {
   560  	var values []interface{}
   561  	for _, subop := range op.subops {
   562  		moreValues, err := subop.Exec(fm)
   563  		if err != nil {
   564  			return nil, err
   565  		}
   566  		values = append(values, moreValues...)
   567  	}
   568  	return values, nil
   569  }
   570  
   571  type funcValuesOp func(*Frame) ([]interface{}, error)
   572  
   573  func (op funcValuesOp) Invoke(fm *Frame) ([]interface{}, error) { return op(fm) }