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