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

     1  package eval
     2  
     3  // Builtin special forms. Special forms behave mostly like ordinary commands -
     4  // they are valid commands syntactically, and can take part in pipelines - but
     5  // they have special rules for the evaluation of their arguments and can affect
     6  // the compilation phase (whereas ordinary commands can only affect the
     7  // evaluation phase).
     8  //
     9  // For instance, the "and" special form evaluates its arguments from left to
    10  // right, and stops as soon as one booleanly false value is obtained: the
    11  // command "and $false (fail haha)" does not produce an exception.
    12  //
    13  // As another instance, the "del" special form removes a variable, affecting the
    14  // compiler.
    15  //
    16  // Flow control structures are also implemented as special forms in elvish, with
    17  // closures functioning as code blocks.
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"strings"
    25  
    26  	"github.com/u-root/u-root/cmds/core/elvish/eval/vals"
    27  	"github.com/u-root/u-root/cmds/core/elvish/eval/vars"
    28  	"github.com/u-root/u-root/cmds/core/elvish/parse"
    29  )
    30  
    31  type compileBuiltin func(*compiler, *parse.Form) OpBody
    32  
    33  var (
    34  	// ErrRelativeUseNotFromMod is thrown by "use" when relative use is used
    35  	// not from a module
    36  	ErrRelativeUseNotFromMod = errors.New("relative use not from module")
    37  	// ErrRelativeUseGoesOutsideLib is thrown when a relative use goes out of
    38  	// the library directory.
    39  	ErrRelativeUseGoesOutsideLib = errors.New("module outside library directory")
    40  )
    41  
    42  var builtinSpecials map[string]compileBuiltin
    43  
    44  // IsBuiltinSpecial is the set of all names of builtin special forms. It is
    45  // intended for external consumption, e.g. the syntax highlighter.
    46  var IsBuiltinSpecial = map[string]bool{}
    47  
    48  func init() {
    49  	// Needed to avoid initialization loop
    50  	builtinSpecials = map[string]compileBuiltin{
    51  		"del": compileDel,
    52  		"fn":  compileFn,
    53  		"use": compileUse,
    54  		"and": compileAnd,
    55  		"or":  compileOr,
    56  	}
    57  	for name := range builtinSpecials {
    58  		IsBuiltinSpecial[name] = true
    59  	}
    60  }
    61  
    62  const delArgMsg = "arguments to del must be variable or variable elements"
    63  
    64  // DelForm = 'del' { VariablePrimary }
    65  func compileDel(cp *compiler, fn *parse.Form) OpBody {
    66  	var ops []Op
    67  	for _, cn := range fn.Args {
    68  		cp.compiling(cn)
    69  		if len(cn.Indexings) != 1 {
    70  			cp.errorf(delArgMsg)
    71  			continue
    72  		}
    73  		head, indicies := cn.Indexings[0].Head, cn.Indexings[0].Indicies
    74  		if head.Type != parse.Bareword {
    75  			if head.Type == parse.Variable {
    76  				cp.errorf("arguments to del must drop $")
    77  			} else {
    78  				cp.errorf(delArgMsg)
    79  			}
    80  			continue
    81  		}
    82  
    83  		explode, ns, name := ParseVariableRef(head.Value)
    84  		if explode {
    85  			cp.errorf("arguments to del may be have a leading @")
    86  			continue
    87  		}
    88  		var f OpBody
    89  		if len(indicies) == 0 {
    90  			switch ns {
    91  			case "", "local":
    92  				if !cp.thisScope().has(name) {
    93  					cp.errorf("no variable $%s in local scope", name)
    94  					continue
    95  				}
    96  				cp.thisScope().del(name)
    97  				f = delLocalVarOp{name}
    98  			case "E":
    99  				f = delEnvVarOp{name}
   100  			default:
   101  				cp.errorf("only variables in local: or E: can be deleted")
   102  				continue
   103  			}
   104  		} else {
   105  			if !cp.registerVariableGet(ns, name) {
   106  				cp.errorf("no variable $%s", head.Value)
   107  				continue
   108  			}
   109  			f = newDelElementOp(ns, name, head.Begin(), head.End(), cp.arrayOps(indicies))
   110  		}
   111  		ops = append(ops, Op{f, cn.Begin(), cn.End()})
   112  	}
   113  	return seqOp{ops}
   114  }
   115  
   116  type delLocalVarOp struct{ name string }
   117  
   118  func (op delLocalVarOp) Invoke(fm *Frame) error {
   119  	delete(fm.local, op.name)
   120  	return nil
   121  }
   122  
   123  type delEnvVarOp struct{ name string }
   124  
   125  func (op delEnvVarOp) Invoke(*Frame) error {
   126  	return os.Unsetenv(op.name)
   127  }
   128  
   129  func newDelElementOp(ns, name string, begin, headEnd int, indexOps []ValuesOp) OpBody {
   130  	ends := make([]int, len(indexOps)+1)
   131  	ends[0] = headEnd
   132  	for i, op := range indexOps {
   133  		ends[i+1] = op.End
   134  	}
   135  	return &delElemOp{ns, name, indexOps, begin, ends}
   136  }
   137  
   138  type delElemOp struct {
   139  	ns       string
   140  	name     string
   141  	indexOps []ValuesOp
   142  	begin    int
   143  	ends     []int
   144  }
   145  
   146  func (op *delElemOp) Invoke(fm *Frame) error {
   147  	var indicies []interface{}
   148  	for _, indexOp := range op.indexOps {
   149  		indexValues, err := indexOp.Exec(fm)
   150  		if err != nil {
   151  			return err
   152  		}
   153  		if len(indexValues) != 1 {
   154  			fm.errorpf(indexOp.Begin, indexOp.End, "index must evaluate to a single value in argument to del")
   155  		}
   156  		indicies = append(indicies, indexValues[0])
   157  	}
   158  	return nil
   159  }
   160  
   161  // FnForm = 'fn' StringPrimary LambdaPrimary
   162  //
   163  // fn f []{foobar} is a shorthand for set '&'f = []{foobar}.
   164  func compileFn(cp *compiler, fn *parse.Form) OpBody {
   165  	args := cp.walkArgs(fn)
   166  	nameNode := args.next()
   167  	varName := mustString(cp, nameNode, "must be a literal string") + FnSuffix
   168  	bodyNode := args.nextMustLambda()
   169  	args.mustEnd()
   170  
   171  	cp.registerVariableSetQname(":" + varName)
   172  	op := cp.lambda(bodyNode)
   173  
   174  	return fnOp{varName, op}
   175  }
   176  
   177  type fnOp struct {
   178  	varName  string
   179  	lambdaOp ValuesOpBody
   180  }
   181  
   182  func (op fnOp) Invoke(fm *Frame) error {
   183  	// Initialize the function variable with the builtin nop function. This step
   184  	// allows the definition of recursive functions; the actual function will
   185  	// never be called.
   186  	fm.local[op.varName] = vars.NewAnyWithInit(NewBuiltinFn("<shouldn't be called>", nop))
   187  	values, err := op.lambdaOp.Invoke(fm)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	closure := values[0].(*Closure)
   192  	closure.Op = wrapFn(closure.Op)
   193  	return fm.local[op.varName].Set(closure)
   194  }
   195  
   196  func wrapFn(op Op) Op {
   197  	return Op{fnWrap{op}, op.Begin, op.End}
   198  }
   199  
   200  type fnWrap struct{ wrapped Op }
   201  
   202  func (op fnWrap) Invoke(fm *Frame) error {
   203  	err := fm.Eval(op.wrapped)
   204  	if err != nil && err.(*Exception).Cause != Return {
   205  		// rethrow
   206  		return err
   207  	}
   208  	return nil
   209  }
   210  
   211  // UseForm = 'use' StringPrimary
   212  func compileUse(cp *compiler, fn *parse.Form) OpBody {
   213  	if len(fn.Args) == 0 {
   214  		end := fn.Head.End()
   215  		cp.errorpf(end, end, "lack module name")
   216  	} else if len(fn.Args) >= 2 {
   217  		cp.errorpf(fn.Args[1].Begin(), fn.Args[len(fn.Args)-1].End(), "superfluous argument(s)")
   218  	}
   219  
   220  	spec := mustString(cp, fn.Args[0], "should be a literal string")
   221  
   222  	// When modspec = "a/b/c:d", modname is c:d, and modpath is a/b/c/d
   223  	modname := spec[strings.LastIndexByte(spec, '/')+1:]
   224  	modpath := strings.Replace(spec, ":", "/", -1)
   225  	cp.thisScope().set(modname + NsSuffix)
   226  
   227  	return useOp{modname, modpath}
   228  }
   229  
   230  type useOp struct{ modname, modpath string }
   231  
   232  func (op useOp) Invoke(fm *Frame) error {
   233  	return use(fm, op.modname, op.modpath)
   234  }
   235  
   236  func use(fm *Frame, modname, modpath string) error {
   237  	resolvedPath := ""
   238  	if strings.HasPrefix(modpath, "./") || strings.HasPrefix(modpath, "../") {
   239  		if fm.srcMeta.typ != SrcModule {
   240  			return ErrRelativeUseNotFromMod
   241  		}
   242  		// Resolve relative modpath.
   243  		resolvedPath = filepath.Clean(filepath.Dir(fm.srcMeta.name) + "/" + modpath)
   244  	} else {
   245  		resolvedPath = filepath.Clean(modpath)
   246  	}
   247  	if strings.HasPrefix(resolvedPath, "../") {
   248  		return ErrRelativeUseGoesOutsideLib
   249  	}
   250  
   251  	// Put the just loaded module into local scope.
   252  	ns, err := loadModule(fm, resolvedPath)
   253  	if err != nil {
   254  		return err
   255  	}
   256  	fm.local.AddNs(modname, ns)
   257  	return nil
   258  }
   259  
   260  func loadModule(fm *Frame, name string) (Ns, error) {
   261  	if ns, ok := fm.Evaler.modules[name]; ok {
   262  		// Module already loaded.
   263  		return ns, nil
   264  	}
   265  
   266  	// Load the source.
   267  	src, err := getModuleSource(fm.Evaler, name)
   268  	if err != nil {
   269  		return nil, err
   270  	}
   271  
   272  	n, err := parse.Parse(name, src.code)
   273  	if err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	// Make an empty scope to evaluate the module in.
   278  	modGlobal := Ns{}
   279  
   280  	newFm := &Frame{
   281  		fm.Evaler, src,
   282  		modGlobal, make(Ns),
   283  		fm.ports,
   284  		0, len(src.code), fm.addTraceback(), false,
   285  	}
   286  
   287  	op, err := compile(newFm.Builtin.static(), modGlobal.static(), n, src)
   288  	if err != nil {
   289  		return nil, err
   290  	}
   291  
   292  	// Load the namespace before executing. This prevent circular "use"es from
   293  	// resulting in an infinite recursion.
   294  	fm.Evaler.modules[name] = modGlobal
   295  	err = newFm.Eval(op)
   296  	if err != nil {
   297  		// Unload the namespace.
   298  		delete(fm.modules, name)
   299  		return nil, err
   300  	}
   301  	return modGlobal, nil
   302  }
   303  
   304  func getModuleSource(ev *Evaler, name string) (*Source, error) {
   305  	// First try loading from file.
   306  	path := filepath.Join(ev.libDir, name+".elv")
   307  	if ev.libDir != "" {
   308  		_, err := os.Stat(path)
   309  		if err == nil {
   310  			code, err := readFileUTF8(path)
   311  			if err != nil {
   312  				return nil, err
   313  			}
   314  			return NewModuleSource(name, path, code), nil
   315  		} else if !os.IsNotExist(err) {
   316  			return nil, err
   317  		}
   318  	}
   319  
   320  	// Try loading bundled module.
   321  	if code, ok := ev.bundled[name]; ok {
   322  		return NewModuleSource(name, "", code), nil
   323  	}
   324  
   325  	return nil, fmt.Errorf("cannot load %s: %s does not exist", name, path)
   326  }
   327  
   328  // compileAnd compiles the "and" special form.
   329  //
   330  // The and special form evaluates arguments until a false-ish values is found
   331  // and outputs it; the remaining arguments are not evaluated. If there are no
   332  // false-ish values, the last value is output. If there are no arguments, it
   333  // outputs $true, as if there is a hidden $true before actual arguments.
   334  func compileAnd(cp *compiler, fn *parse.Form) OpBody {
   335  	return &andOrOp{cp.compoundOps(fn.Args), true, false}
   336  }
   337  
   338  // compileOr compiles the "or" special form.
   339  //
   340  // The or special form evaluates arguments until a true-ish values is found and
   341  // outputs it; the remaining arguments are not evaluated. If there are no
   342  // true-ish values, the last value is output. If there are no arguments, it
   343  // outputs $false, as if there is a hidden $false before actual arguments.
   344  func compileOr(cp *compiler, fn *parse.Form) OpBody {
   345  	return &andOrOp{cp.compoundOps(fn.Args), false, true}
   346  }
   347  
   348  type andOrOp struct {
   349  	argOps []ValuesOp
   350  	init   bool
   351  	stopAt bool
   352  }
   353  
   354  func (op *andOrOp) Invoke(fm *Frame) error {
   355  	var lastValue interface{} = vals.Bool(op.init)
   356  	for _, argOp := range op.argOps {
   357  		values, err := argOp.Exec(fm)
   358  		if err != nil {
   359  			return err
   360  		}
   361  		for _, value := range values {
   362  			if vals.Bool(value) == op.stopAt {
   363  				fm.OutputChan() <- value
   364  				return nil
   365  			}
   366  			lastValue = value
   367  		}
   368  	}
   369  	fm.OutputChan() <- lastValue
   370  	return nil
   371  }
   372  
   373  func compileIf(cp *compiler, fn *parse.Form) OpBody {
   374  	args := cp.walkArgs(fn)
   375  	var condNodes []*parse.Compound
   376  	var bodyNodes []*parse.Primary
   377  	for {
   378  		condNodes = append(condNodes, args.next())
   379  		bodyNodes = append(bodyNodes, args.nextMustLambda())
   380  		if !args.nextIs("elif") {
   381  			break
   382  		}
   383  	}
   384  	elseNode := args.nextMustLambdaIfAfter("else")
   385  	args.mustEnd()
   386  
   387  	condOps := cp.compoundOps(condNodes)
   388  	bodyOps := cp.primaryOps(bodyNodes)
   389  	var elseOp ValuesOp
   390  	if elseNode != nil {
   391  		elseOp = cp.primaryOp(elseNode)
   392  	}
   393  
   394  	return &ifOp{condOps, bodyOps, elseOp}
   395  }
   396  
   397  type ifOp struct {
   398  	condOps []ValuesOp
   399  	bodyOps []ValuesOp
   400  	elseOp  ValuesOp
   401  }
   402  
   403  func (op *ifOp) Invoke(fm *Frame) error {
   404  	bodies := make([]Callable, len(op.bodyOps))
   405  	for i, bodyOp := range op.bodyOps {
   406  		bodies[i] = bodyOp.execlambdaOp(fm)
   407  	}
   408  	else_ := op.elseOp.execlambdaOp(fm)
   409  	for i, condOp := range op.condOps {
   410  		condValues, err := condOp.Exec(fm.fork("if cond"))
   411  		if err != nil {
   412  			return err
   413  		}
   414  		if allTrue(condValues) {
   415  			return bodies[i].Call(fm.fork("if body"), NoArgs, NoOpts)
   416  		}
   417  	}
   418  	if op.elseOp.Body != nil {
   419  		return else_.Call(fm.fork("if else"), NoArgs, NoOpts)
   420  	}
   421  	return nil
   422  }
   423  
   424  func compileWhile(cp *compiler, fn *parse.Form) OpBody {
   425  	args := cp.walkArgs(fn)
   426  	condNode := args.next()
   427  	bodyNode := args.nextMustLambda()
   428  	args.mustEnd()
   429  
   430  	return &whileOp{cp.compoundOp(condNode), cp.primaryOp(bodyNode)}
   431  }
   432  
   433  type whileOp struct {
   434  	condOp, bodyOp ValuesOp
   435  }
   436  
   437  func (op *whileOp) Invoke(fm *Frame) error {
   438  	body := op.bodyOp.execlambdaOp(fm)
   439  
   440  	for {
   441  		condValues, err := op.condOp.Exec(fm.fork("while cond"))
   442  		if err != nil {
   443  			return err
   444  		}
   445  		if !allTrue(condValues) {
   446  			break
   447  		}
   448  		err = fm.fork("while").Call(body, NoArgs, NoOpts)
   449  		if err != nil {
   450  			exc := err.(*Exception)
   451  			if exc.Cause == Continue {
   452  				// do nothing
   453  			} else if exc.Cause == Break {
   454  				break
   455  			} else {
   456  				return err
   457  			}
   458  		}
   459  	}
   460  	return nil
   461  }
   462  
   463  func compileFor(cp *compiler, fn *parse.Form) OpBody {
   464  	args := cp.walkArgs(fn)
   465  	varNode := args.next()
   466  	iterNode := args.next()
   467  	bodyNode := args.nextMustLambda()
   468  	elseNode := args.nextMustLambdaIfAfter("else")
   469  	args.mustEnd()
   470  
   471  	varOp, restOp := cp.lvaluesOp(varNode.Indexings[0])
   472  	if restOp.Body != nil {
   473  		cp.errorpf(restOp.Begin, restOp.End, "rest not allowed")
   474  	}
   475  
   476  	iterOp := cp.compoundOp(iterNode)
   477  	bodyOp := cp.primaryOp(bodyNode)
   478  	var elseOp ValuesOp
   479  	if elseNode != nil {
   480  		elseOp = cp.primaryOp(elseNode)
   481  	}
   482  
   483  	return &forOp{varOp, iterOp, bodyOp, elseOp}
   484  }
   485  
   486  type forOp struct {
   487  	varOp  LValuesOp
   488  	iterOp ValuesOp
   489  	bodyOp ValuesOp
   490  	elseOp ValuesOp
   491  }
   492  
   493  func (op *forOp) Invoke(fm *Frame) error {
   494  	variables, err := op.varOp.Exec(fm)
   495  	if err != nil {
   496  		return err
   497  	}
   498  	if len(variables) != 1 {
   499  		fm.errorpf(op.varOp.Begin, op.varOp.End, "only one variable allowed")
   500  	}
   501  	variable := variables[0]
   502  	iterable := fm.ExecAndUnwrap("value being iterated", op.iterOp).One().Any()
   503  
   504  	body := op.bodyOp.execlambdaOp(fm)
   505  	elseBody := op.elseOp.execlambdaOp(fm)
   506  
   507  	iterated := false
   508  	var errElement error
   509  	errIterate := vals.Iterate(iterable, func(v interface{}) bool {
   510  		iterated = true
   511  		err := variable.Set(v)
   512  		if err != nil {
   513  			errElement = err
   514  			return false
   515  		}
   516  		err = fm.fork("for").Call(body, NoArgs, NoOpts)
   517  		if err != nil {
   518  			exc := err.(*Exception)
   519  			if exc.Cause == Continue {
   520  				// do nothing
   521  			} else if exc.Cause == Break {
   522  				return false
   523  			} else {
   524  				errElement = err
   525  				return false
   526  			}
   527  		}
   528  		return true
   529  	})
   530  	if errIterate != nil {
   531  		return errIterate
   532  	}
   533  	if errElement != nil {
   534  		return errElement
   535  	}
   536  
   537  	if !iterated && elseBody != nil {
   538  		return elseBody.Call(fm.fork("for else"), NoArgs, NoOpts)
   539  	}
   540  	return nil
   541  }
   542  
   543  func compileTry(cp *compiler, fn *parse.Form) OpBody {
   544  	logger.Println("compiling try")
   545  	args := cp.walkArgs(fn)
   546  	bodyNode := args.nextMustLambda()
   547  	logger.Printf("body is %q", bodyNode.SourceText())
   548  	var exceptVarNode *parse.Indexing
   549  	var exceptNode *parse.Primary
   550  	if args.nextIs("except") {
   551  		logger.Println("except-ing")
   552  		n := args.peek()
   553  		// Is this a variable?
   554  		if len(n.Indexings) == 1 && n.Indexings[0].Head.Type == parse.Bareword {
   555  			exceptVarNode = n.Indexings[0]
   556  			args.next()
   557  		}
   558  		exceptNode = args.nextMustLambda()
   559  	}
   560  	elseNode := args.nextMustLambdaIfAfter("else")
   561  	finallyNode := args.nextMustLambdaIfAfter("finally")
   562  	args.mustEnd()
   563  
   564  	var exceptVarOp LValuesOp
   565  	var bodyOp, exceptOp, elseOp, finallyOp ValuesOp
   566  	bodyOp = cp.primaryOp(bodyNode)
   567  	if exceptVarNode != nil {
   568  		var restOp LValuesOp
   569  		exceptVarOp, restOp = cp.lvaluesOp(exceptVarNode)
   570  		if restOp.Body != nil {
   571  			cp.errorpf(restOp.Begin, restOp.End, "may not use @rest in except variable")
   572  		}
   573  	}
   574  	if exceptNode != nil {
   575  		exceptOp = cp.primaryOp(exceptNode)
   576  	}
   577  	if elseNode != nil {
   578  		elseOp = cp.primaryOp(elseNode)
   579  	}
   580  	if finallyNode != nil {
   581  		finallyOp = cp.primaryOp(finallyNode)
   582  	}
   583  
   584  	return &tryOp{bodyOp, exceptVarOp, exceptOp, elseOp, finallyOp}
   585  }
   586  
   587  type tryOp struct {
   588  	bodyOp      ValuesOp
   589  	exceptVarOp LValuesOp
   590  	exceptOp    ValuesOp
   591  	elseOp      ValuesOp
   592  	finallyOp   ValuesOp
   593  }
   594  
   595  func (op *tryOp) Invoke(fm *Frame) error {
   596  	body := op.bodyOp.execlambdaOp(fm)
   597  	exceptVar := op.exceptVarOp.execMustOne(fm)
   598  	except := op.exceptOp.execlambdaOp(fm)
   599  	else_ := op.elseOp.execlambdaOp(fm)
   600  	finally := op.finallyOp.execlambdaOp(fm)
   601  
   602  	err := fm.fork("try body").Call(body, NoArgs, NoOpts)
   603  	if err != nil {
   604  		if except != nil {
   605  			if exceptVar != nil {
   606  				err := exceptVar.Set(err.(*Exception))
   607  				if err != nil {
   608  					return err
   609  				}
   610  			}
   611  			err = fm.fork("try except").Call(except, NoArgs, NoOpts)
   612  		}
   613  	} else {
   614  		if else_ != nil {
   615  			err = fm.fork("try else").Call(else_, NoArgs, NoOpts)
   616  		}
   617  	}
   618  	if finally != nil {
   619  		errFinally := finally.Call(fm.fork("try finally"), NoArgs, NoOpts)
   620  		if errFinally != nil {
   621  			// TODO: If err is not nil, this discards err. Use something similar
   622  			// to pipeline exception to expose both.
   623  			return errFinally
   624  		}
   625  	}
   626  	return err
   627  }
   628  
   629  // execLambdaOp executes a ValuesOp that is known to yield a lambda and returns
   630  // the lambda. If the ValuesOp is empty, it returns a nil.
   631  func (op ValuesOp) execlambdaOp(fm *Frame) Callable {
   632  	if op.Body == nil {
   633  		return nil
   634  	}
   635  
   636  	values, err := op.Exec(fm)
   637  	if err != nil {
   638  		panic("must not be erroneous")
   639  	}
   640  	return values[0].(Callable)
   641  }
   642  
   643  // execMustOne executes the LValuesOp and raises an exception if it does not
   644  // evaluate to exactly one Variable. If the given LValuesOp is empty, it returns
   645  // nil.
   646  func (op LValuesOp) execMustOne(fm *Frame) vars.Var {
   647  	if op.Body == nil {
   648  		return nil
   649  	}
   650  	variables, err := op.Exec(fm)
   651  	maybeThrow(err)
   652  	if len(variables) != 1 {
   653  		fm.errorpf(op.Begin, op.End, "should be one variable")
   654  	}
   655  	return variables[0]
   656  }