github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/compile_value.go (about)

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