github.com/elves/elvish@v0.15.0/pkg/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 example, 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 example, 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  	"os"
    21  	"path/filepath"
    22  	"strings"
    23  
    24  	"github.com/elves/elvish/pkg/diag"
    25  	"github.com/elves/elvish/pkg/eval/mods/bundled"
    26  	"github.com/elves/elvish/pkg/eval/vals"
    27  	"github.com/elves/elvish/pkg/eval/vars"
    28  	"github.com/elves/elvish/pkg/parse"
    29  )
    30  
    31  type compileBuiltin func(*compiler, *parse.Form) effectOp
    32  
    33  var builtinSpecials map[string]compileBuiltin
    34  
    35  // IsBuiltinSpecial is the set of all names of builtin special forms. It is
    36  // intended for external consumption, e.g. the syntax highlighter.
    37  var IsBuiltinSpecial = map[string]bool{}
    38  
    39  type noSuchModule struct{ spec string }
    40  
    41  func (err noSuchModule) Error() string { return "no such module: " + err.spec }
    42  
    43  func init() {
    44  	// Needed to avoid initialization loop
    45  	builtinSpecials = map[string]compileBuiltin{
    46  		"var": compileVar,
    47  		"set": compileSet,
    48  		"del": compileDel,
    49  		"fn":  compileFn,
    50  
    51  		"use": compileUse,
    52  
    53  		"and": compileAnd,
    54  		"or":  compileOr,
    55  
    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  // VarForm = 'var' { VariablePrimary } [ '=' { Compound } ]
    67  func compileVar(cp *compiler, fn *parse.Form) effectOp {
    68  	lhs := lvaluesGroup{rest: -1}
    69  	for i, cn := range fn.Args {
    70  		if parse.SourceText(cn) == "=" {
    71  			var rhs valuesOp
    72  			if i == len(fn.Args)-1 {
    73  				rhs = nopValuesOp{diag.PointRanging(fn.Range().To)}
    74  			} else {
    75  				rhs = seqValuesOp{
    76  					diag.MixedRanging(fn.Args[i+1], fn.Args[len(fn.Args)-1]),
    77  					cp.compoundOps(fn.Args[i+1:])}
    78  			}
    79  			return &assignOp{fn.Range(), lhs, rhs}
    80  		}
    81  		if len(cn.Indexings) != 1 {
    82  			cp.errorpf(cn, "variable name must be a single string literal")
    83  		}
    84  		if len(cn.Indexings[0].Indicies) > 0 {
    85  			cp.errorpf(cn, "variable name must not have indicies")
    86  		}
    87  		pn := cn.Indexings[0].Head
    88  		if !parse.ValidLHSVariable(pn, true) {
    89  			cp.errorpf(cn, "invalid variable name")
    90  		}
    91  
    92  		name := pn.Value
    93  		if !IsUnqualified(name) {
    94  			cp.errorpf(cn, "variable declared in var must be unqualified")
    95  		}
    96  		sigil, name := SplitSigil(name)
    97  		if sigil == "@" {
    98  			if lhs.rest != -1 {
    99  				cp.errorpf(cn, "multiple variable names with @ not allowed")
   100  			}
   101  			lhs.rest = i
   102  		}
   103  		slotIndex := cp.thisScope().add(name)
   104  		lhs.lvalues = append(lhs.lvalues,
   105  			lvalue{cn.Range(), &varRef{localScope, slotIndex, nil}, nil, nil})
   106  	}
   107  	// If there is no assignment, there is no work to be done at eval-time.
   108  	return nopOp{}
   109  }
   110  
   111  // IsUnqualified returns whether name is an unqualified variable name.
   112  func IsUnqualified(name string) bool {
   113  	i := strings.IndexByte(name, ':')
   114  	return i == -1 || i == len(name)-1
   115  }
   116  
   117  // SetForm = 'set' { LHS } '=' { Compound }
   118  func compileSet(cp *compiler, fn *parse.Form) effectOp {
   119  	eq := -1
   120  	for i, cn := range fn.Args {
   121  		if parse.SourceText(cn) == "=" {
   122  			eq = i
   123  			break
   124  		}
   125  	}
   126  	if eq == -1 {
   127  		cp.errorpf(diag.PointRanging(fn.Range().To), "need = and right-hand-side")
   128  	}
   129  	lhs := cp.parseCompoundLValues(fn.Args[:eq])
   130  	var rhs valuesOp
   131  	if eq == len(fn.Args)-1 {
   132  		rhs = nopValuesOp{diag.PointRanging(fn.Range().To)}
   133  	} else {
   134  		rhs = seqValuesOp{
   135  			diag.MixedRanging(fn.Args[eq+1], fn.Args[len(fn.Args)-1]),
   136  			cp.compoundOps(fn.Args[eq+1:])}
   137  	}
   138  	return &assignOp{fn.Range(), lhs, rhs}
   139  
   140  }
   141  
   142  const delArgMsg = "arguments to del must be variable or variable elements"
   143  
   144  // DelForm = 'del' { LHS }
   145  func compileDel(cp *compiler, fn *parse.Form) effectOp {
   146  	var ops []effectOp
   147  	for _, cn := range fn.Args {
   148  		if len(cn.Indexings) != 1 {
   149  			cp.errorpf(cn, delArgMsg)
   150  			continue
   151  		}
   152  		head, indices := cn.Indexings[0].Head, cn.Indexings[0].Indicies
   153  		if head.Type == parse.Variable {
   154  			cp.errorpf(cn, "arguments to del must drop $")
   155  		} else if !parse.ValidLHSVariable(head, false) {
   156  			cp.errorpf(cn, delArgMsg)
   157  		}
   158  
   159  		qname := head.Value
   160  		var f effectOp
   161  		ref := resolveVarRef(cp, qname, nil)
   162  		if ref == nil {
   163  			cp.errorpf(cn, "no variable $%s", head.Value)
   164  			continue
   165  		}
   166  		if len(indices) == 0 {
   167  			if ref.scope == envScope {
   168  				f = delEnvVarOp{fn.Range(), ref.subNames[0]}
   169  			} else if ref.scope == localScope && len(ref.subNames) == 0 {
   170  				f = delLocalVarOp{ref.index}
   171  				cp.thisScope().deleted[ref.index] = true
   172  			} else {
   173  				cp.errorpf(cn, "only variables in local: or E: can be deleted")
   174  				continue
   175  			}
   176  		} else {
   177  			f = newDelElementOp(ref, head.Range().From, head.Range().To, cp.arrayOps(indices))
   178  		}
   179  		ops = append(ops, f)
   180  	}
   181  	return seqOp{ops}
   182  }
   183  
   184  type delLocalVarOp struct{ index int }
   185  
   186  func (op delLocalVarOp) exec(fm *Frame) Exception {
   187  	fm.local.slots[op.index] = nil
   188  	return nil
   189  }
   190  
   191  type delEnvVarOp struct {
   192  	diag.Ranging
   193  	name string
   194  }
   195  
   196  func (op delEnvVarOp) exec(fm *Frame) Exception {
   197  	return fm.errorp(op, os.Unsetenv(op.name))
   198  }
   199  
   200  func newDelElementOp(ref *varRef, begin, headEnd int, indexOps []valuesOp) effectOp {
   201  	ends := make([]int, len(indexOps)+1)
   202  	ends[0] = headEnd
   203  	for i, op := range indexOps {
   204  		ends[i+1] = op.Range().To
   205  	}
   206  	return &delElemOp{ref, indexOps, begin, ends}
   207  }
   208  
   209  type delElemOp struct {
   210  	ref      *varRef
   211  	indexOps []valuesOp
   212  	begin    int
   213  	ends     []int
   214  }
   215  
   216  func (op *delElemOp) Range() diag.Ranging {
   217  	return diag.Ranging{From: op.begin, To: op.ends[0]}
   218  }
   219  
   220  func (op *delElemOp) exec(fm *Frame) Exception {
   221  	var indices []interface{}
   222  	for _, indexOp := range op.indexOps {
   223  		indexValues, exc := indexOp.exec(fm)
   224  		if exc != nil {
   225  			return exc
   226  		}
   227  		if len(indexValues) != 1 {
   228  			return fm.errorpf(indexOp, "index must evaluate to a single value in argument to del")
   229  		}
   230  		indices = append(indices, indexValues[0])
   231  	}
   232  	err := vars.DelElement(deref(fm, op.ref), indices)
   233  	if err != nil {
   234  		if level := vars.ElementErrorLevel(err); level >= 0 {
   235  			return fm.errorp(diag.Ranging{From: op.begin, To: op.ends[level]}, err)
   236  		}
   237  		return fm.errorp(op, err)
   238  	}
   239  	return nil
   240  }
   241  
   242  // FnForm = 'fn' StringPrimary LambdaPrimary
   243  //
   244  // fn f []{foobar} is a shorthand for set '&'f = []{foobar}.
   245  func compileFn(cp *compiler, fn *parse.Form) effectOp {
   246  	args := cp.walkArgs(fn)
   247  	nameNode := args.next()
   248  	name := mustString(cp, nameNode, "must be a literal string")
   249  	bodyNode := args.nextMustLambda()
   250  	args.mustEnd()
   251  
   252  	// Define the variable before compiling the body, so that the body may refer
   253  	// to the function itself.
   254  	index := cp.thisScope().add(name + FnSuffix)
   255  	op := cp.lambda(bodyNode)
   256  
   257  	return fnOp{nameNode.Range(), index, op}
   258  }
   259  
   260  type fnOp struct {
   261  	keywordRange diag.Ranging
   262  	varIndex     int
   263  	lambdaOp     valuesOp
   264  }
   265  
   266  func (op fnOp) exec(fm *Frame) Exception {
   267  	// Initialize the function variable with the builtin nop function. This step
   268  	// allows the definition of recursive functions; the actual function will
   269  	// never be called.
   270  	fm.local.slots[op.varIndex].Set(NewGoFn("<shouldn't be called>", nop))
   271  	values, exc := op.lambdaOp.exec(fm)
   272  	if exc != nil {
   273  		return exc
   274  	}
   275  	c := values[0].(*closure)
   276  	c.Op = fnWrap{c.Op}
   277  	return fm.errorp(op.keywordRange, fm.local.slots[op.varIndex].Set(c))
   278  }
   279  
   280  type fnWrap struct{ effectOp }
   281  
   282  func (op fnWrap) Range() diag.Ranging { return op.effectOp.(diag.Ranger).Range() }
   283  
   284  func (op fnWrap) exec(fm *Frame) Exception {
   285  	exc := op.effectOp.exec(fm)
   286  	if exc != nil && exc.Reason() != Return {
   287  		// rethrow
   288  		return exc
   289  	}
   290  	return nil
   291  }
   292  
   293  // UseForm = 'use' StringPrimary
   294  func compileUse(cp *compiler, fn *parse.Form) effectOp {
   295  	var name, spec string
   296  
   297  	switch len(fn.Args) {
   298  	case 0:
   299  		end := fn.Head.Range().To
   300  		cp.errorpf(diag.PointRanging(end), "lack module name")
   301  	case 1:
   302  		spec = mustString(cp, fn.Args[0],
   303  			"module spec should be a literal string")
   304  		// Use the last path component as the name; for instance, if path =
   305  		// "a/b/c/d", name is "d". If path doesn't have slashes, name = path.
   306  		name = spec[strings.LastIndexByte(spec, '/')+1:]
   307  	case 2:
   308  		// TODO(xiaq): Allow using variable as module path
   309  		spec = mustString(cp, fn.Args[0],
   310  			"module spec should be a literal string")
   311  		name = mustString(cp, fn.Args[1],
   312  			"module name should be a literal string")
   313  	default: // > 2
   314  		cp.errorpf(diag.MixedRanging(fn.Args[2], fn.Args[len(fn.Args)-1]),
   315  			"superfluous argument(s)")
   316  	}
   317  
   318  	return useOp{fn.Range(), cp.thisScope().add(name + NsSuffix), spec}
   319  }
   320  
   321  type useOp struct {
   322  	diag.Ranging
   323  	varIndex int
   324  	spec     string
   325  }
   326  
   327  func (op useOp) exec(fm *Frame) Exception {
   328  	ns, err := use(fm, op.spec, op)
   329  	if err != nil {
   330  		return fm.errorp(op, err)
   331  	}
   332  	fm.local.slots[op.varIndex].Set(ns)
   333  	return nil
   334  }
   335  
   336  var bundledModules = bundled.Get()
   337  
   338  func use(fm *Frame, spec string, r diag.Ranger) (*Ns, error) {
   339  	if strings.HasPrefix(spec, "./") || strings.HasPrefix(spec, "../") {
   340  		var dir string
   341  		if fm.srcMeta.IsFile {
   342  			dir = filepath.Dir(fm.srcMeta.Name)
   343  		} else {
   344  			var err error
   345  			dir, err = os.Getwd()
   346  			if err != nil {
   347  				return nil, err
   348  			}
   349  		}
   350  		path := filepath.Clean(dir + "/" + spec + ".elv")
   351  		return useFromFile(fm, spec, path, r)
   352  	}
   353  	if ns, ok := fm.Evaler.modules[spec]; ok {
   354  		return ns, nil
   355  	}
   356  	if code, ok := bundledModules[spec]; ok {
   357  		return evalModule(fm, spec,
   358  			parse.Source{Name: "[bundled " + spec + "]", Code: code}, r)
   359  	}
   360  	libDir := fm.Evaler.getLibDir()
   361  	if libDir == "" {
   362  		return nil, noSuchModule{spec}
   363  	}
   364  	return useFromFile(fm, spec, libDir+"/"+spec+".elv", r)
   365  }
   366  
   367  // TODO: Make access to fm.Evaler.modules concurrency-safe.
   368  func useFromFile(fm *Frame, spec, path string, r diag.Ranger) (*Ns, error) {
   369  	if ns, ok := fm.Evaler.modules[path]; ok {
   370  		return ns, nil
   371  	}
   372  	code, err := readFileUTF8(path)
   373  	if err != nil {
   374  		if os.IsNotExist(err) {
   375  			return nil, noSuchModule{spec}
   376  		}
   377  		return nil, err
   378  	}
   379  	return evalModule(fm, path, parse.Source{Name: path, Code: code, IsFile: true}, r)
   380  }
   381  
   382  // TODO: Make access to fm.Evaler.modules concurrency-safe.
   383  func evalModule(fm *Frame, key string, src parse.Source, r diag.Ranger) (*Ns, error) {
   384  	ns, exec, err := fm.PrepareEval(src, r, new(Ns))
   385  	if err != nil {
   386  		return nil, err
   387  	}
   388  	// Installs the namespace before executing. This prevent circular use'es
   389  	// from resulting in an infinite recursion.
   390  	fm.Evaler.modules[key] = ns
   391  	err = exec()
   392  	if err != nil {
   393  		// Unload the namespace.
   394  		delete(fm.Evaler.modules, key)
   395  		return nil, err
   396  	}
   397  	return ns, nil
   398  }
   399  
   400  // compileAnd compiles the "and" special form.
   401  //
   402  // The and special form evaluates arguments until a false-ish values is found
   403  // and outputs it; the remaining arguments are not evaluated. If there are no
   404  // false-ish values, the last value is output. If there are no arguments, it
   405  // outputs $true, as if there is a hidden $true before actual arguments.
   406  func compileAnd(cp *compiler, fn *parse.Form) effectOp {
   407  	return &andOrOp{cp.compoundOps(fn.Args), true, false}
   408  }
   409  
   410  // compileOr compiles the "or" special form.
   411  //
   412  // The or special form evaluates arguments until a true-ish values is found and
   413  // outputs it; the remaining arguments are not evaluated. If there are no
   414  // true-ish values, the last value is output. If there are no arguments, it
   415  // outputs $false, as if there is a hidden $false before actual arguments.
   416  func compileOr(cp *compiler, fn *parse.Form) effectOp {
   417  	return &andOrOp{cp.compoundOps(fn.Args), false, true}
   418  }
   419  
   420  type andOrOp struct {
   421  	argOps []valuesOp
   422  	init   bool
   423  	stopAt bool
   424  }
   425  
   426  func (op *andOrOp) exec(fm *Frame) Exception {
   427  	var lastValue interface{} = vals.Bool(op.init)
   428  	for _, argOp := range op.argOps {
   429  		values, exc := argOp.exec(fm)
   430  		if exc != nil {
   431  			return exc
   432  		}
   433  		for _, value := range values {
   434  			if vals.Bool(value) == op.stopAt {
   435  				fm.OutputChan() <- value
   436  				return nil
   437  			}
   438  			lastValue = value
   439  		}
   440  	}
   441  	fm.OutputChan() <- lastValue
   442  	return nil
   443  }
   444  
   445  func compileIf(cp *compiler, fn *parse.Form) effectOp {
   446  	args := cp.walkArgs(fn)
   447  	var condNodes []*parse.Compound
   448  	var bodyNodes []*parse.Primary
   449  	for {
   450  		condNodes = append(condNodes, args.next())
   451  		bodyNodes = append(bodyNodes, args.nextMustLambda())
   452  		if !args.nextIs("elif") {
   453  			break
   454  		}
   455  	}
   456  	elseNode := args.nextMustLambdaIfAfter("else")
   457  	args.mustEnd()
   458  
   459  	condOps := cp.compoundOps(condNodes)
   460  	bodyOps := cp.primaryOps(bodyNodes)
   461  	var elseOp valuesOp
   462  	if elseNode != nil {
   463  		elseOp = cp.primaryOp(elseNode)
   464  	}
   465  
   466  	return &ifOp{fn.Range(), condOps, bodyOps, elseOp}
   467  }
   468  
   469  type ifOp struct {
   470  	diag.Ranging
   471  	condOps []valuesOp
   472  	bodyOps []valuesOp
   473  	elseOp  valuesOp
   474  }
   475  
   476  func (op *ifOp) exec(fm *Frame) Exception {
   477  	bodies := make([]Callable, len(op.bodyOps))
   478  	for i, bodyOp := range op.bodyOps {
   479  		bodies[i] = execLambdaOp(fm, bodyOp)
   480  	}
   481  	elseFn := execLambdaOp(fm, op.elseOp)
   482  	for i, condOp := range op.condOps {
   483  		condValues, exc := condOp.exec(fm.fork("if cond"))
   484  		if exc != nil {
   485  			return exc
   486  		}
   487  		if allTrue(condValues) {
   488  			return fm.errorp(op, bodies[i].Call(fm.fork("if body"), NoArgs, NoOpts))
   489  		}
   490  	}
   491  	if op.elseOp != nil {
   492  		return fm.errorp(op, elseFn.Call(fm.fork("if else"), NoArgs, NoOpts))
   493  	}
   494  	return nil
   495  }
   496  
   497  func compileWhile(cp *compiler, fn *parse.Form) effectOp {
   498  	args := cp.walkArgs(fn)
   499  	condNode := args.next()
   500  	bodyNode := args.nextMustLambda()
   501  	elseNode := args.nextMustLambdaIfAfter("else")
   502  	args.mustEnd()
   503  
   504  	condOp := cp.compoundOp(condNode)
   505  	bodyOp := cp.primaryOp(bodyNode)
   506  	var elseOp valuesOp
   507  	if elseNode != nil {
   508  		elseOp = cp.primaryOp(elseNode)
   509  	}
   510  
   511  	return &whileOp{fn.Range(), condOp, bodyOp, elseOp}
   512  }
   513  
   514  type whileOp struct {
   515  	diag.Ranging
   516  	condOp, bodyOp, elseOp valuesOp
   517  }
   518  
   519  func (op *whileOp) exec(fm *Frame) Exception {
   520  	body := execLambdaOp(fm, op.bodyOp)
   521  	elseBody := execLambdaOp(fm, op.elseOp)
   522  
   523  	iterated := false
   524  	for {
   525  		condValues, exc := op.condOp.exec(fm.fork("while cond"))
   526  		if exc != nil {
   527  			return exc
   528  		}
   529  		if !allTrue(condValues) {
   530  			break
   531  		}
   532  		iterated = true
   533  		err := body.Call(fm.fork("while"), NoArgs, NoOpts)
   534  		if err != nil {
   535  			exc := err.(Exception)
   536  			if exc.Reason() == Continue {
   537  				// Do nothing
   538  			} else if exc.Reason() == Break {
   539  				break
   540  			} else {
   541  				return exc
   542  			}
   543  		}
   544  	}
   545  
   546  	if op.elseOp != nil && !iterated {
   547  		return fm.errorp(op, elseBody.Call(fm.fork("while else"), NoArgs, NoOpts))
   548  	}
   549  	return nil
   550  }
   551  
   552  func compileFor(cp *compiler, fn *parse.Form) effectOp {
   553  	args := cp.walkArgs(fn)
   554  	varNode := args.next()
   555  	iterNode := args.next()
   556  	bodyNode := args.nextMustLambda()
   557  	elseNode := args.nextMustLambdaIfAfter("else")
   558  	args.mustEnd()
   559  
   560  	lvalue := cp.compileOneLValue(varNode)
   561  
   562  	iterOp := cp.compoundOp(iterNode)
   563  	bodyOp := cp.primaryOp(bodyNode)
   564  	var elseOp valuesOp
   565  	if elseNode != nil {
   566  		elseOp = cp.primaryOp(elseNode)
   567  	}
   568  
   569  	return &forOp{fn.Range(), lvalue, iterOp, bodyOp, elseOp}
   570  }
   571  
   572  type forOp struct {
   573  	diag.Ranging
   574  	lvalue lvalue
   575  	iterOp valuesOp
   576  	bodyOp valuesOp
   577  	elseOp valuesOp
   578  }
   579  
   580  func (op *forOp) exec(fm *Frame) Exception {
   581  	variable, err := derefLValue(fm, op.lvalue)
   582  	if err != nil {
   583  		return fm.errorp(op, err)
   584  	}
   585  	iterable, err := evalForValue(fm, op.iterOp, "value being iterated")
   586  	if err != nil {
   587  		return fm.errorp(op, err)
   588  	}
   589  
   590  	body := execLambdaOp(fm, op.bodyOp)
   591  	elseBody := execLambdaOp(fm, op.elseOp)
   592  
   593  	iterated := false
   594  	var errElement error
   595  	errIterate := vals.Iterate(iterable, func(v interface{}) bool {
   596  		iterated = true
   597  		err := variable.Set(v)
   598  		if err != nil {
   599  			errElement = err
   600  			return false
   601  		}
   602  		err = body.Call(fm.fork("for"), NoArgs, NoOpts)
   603  		if err != nil {
   604  			exc := err.(Exception)
   605  			if exc.Reason() == Continue {
   606  				// do nothing
   607  			} else if exc.Reason() == Break {
   608  				return false
   609  			} else {
   610  				errElement = err
   611  				return false
   612  			}
   613  		}
   614  		return true
   615  	})
   616  	if errIterate != nil {
   617  		return fm.errorp(op, errIterate)
   618  	}
   619  	if errElement != nil {
   620  		return fm.errorp(op, errElement)
   621  	}
   622  
   623  	if !iterated && elseBody != nil {
   624  		return fm.errorp(op, elseBody.Call(fm.fork("for else"), NoArgs, NoOpts))
   625  	}
   626  	return nil
   627  }
   628  
   629  func compileTry(cp *compiler, fn *parse.Form) effectOp {
   630  	logger.Println("compiling try")
   631  	args := cp.walkArgs(fn)
   632  	bodyNode := args.nextMustLambda()
   633  	logger.Printf("body is %q", parse.SourceText(bodyNode))
   634  	var exceptVarNode *parse.Compound
   635  	var exceptNode *parse.Primary
   636  	if args.nextIs("except") {
   637  		logger.Println("except-ing")
   638  		n := args.peek()
   639  		// Is this a variable?
   640  		if len(n.Indexings) == 1 && n.Indexings[0].Head.Type == parse.Bareword {
   641  			exceptVarNode = n
   642  			args.next()
   643  		}
   644  		exceptNode = args.nextMustLambda()
   645  	}
   646  	elseNode := args.nextMustLambdaIfAfter("else")
   647  	finallyNode := args.nextMustLambdaIfAfter("finally")
   648  	args.mustEnd()
   649  
   650  	var exceptVar lvalue
   651  	var bodyOp, exceptOp, elseOp, finallyOp valuesOp
   652  	bodyOp = cp.primaryOp(bodyNode)
   653  	if exceptVarNode != nil {
   654  		exceptVar = cp.compileOneLValue(exceptVarNode)
   655  	}
   656  	if exceptNode != nil {
   657  		exceptOp = cp.primaryOp(exceptNode)
   658  	}
   659  	if elseNode != nil {
   660  		elseOp = cp.primaryOp(elseNode)
   661  	}
   662  	if finallyNode != nil {
   663  		finallyOp = cp.primaryOp(finallyNode)
   664  	}
   665  
   666  	return &tryOp{fn.Range(), bodyOp, exceptVar, exceptOp, elseOp, finallyOp}
   667  }
   668  
   669  type tryOp struct {
   670  	diag.Ranging
   671  	bodyOp    valuesOp
   672  	exceptVar lvalue
   673  	exceptOp  valuesOp
   674  	elseOp    valuesOp
   675  	finallyOp valuesOp
   676  }
   677  
   678  func (op *tryOp) exec(fm *Frame) Exception {
   679  	body := execLambdaOp(fm, op.bodyOp)
   680  	var exceptVar vars.Var
   681  	if op.exceptVar.ref != nil {
   682  		var err error
   683  		exceptVar, err = derefLValue(fm, op.exceptVar)
   684  		if err != nil {
   685  			return fm.errorp(op, err)
   686  		}
   687  	}
   688  	except := execLambdaOp(fm, op.exceptOp)
   689  	elseFn := execLambdaOp(fm, op.elseOp)
   690  	finally := execLambdaOp(fm, op.finallyOp)
   691  
   692  	err := body.Call(fm.fork("try body"), NoArgs, NoOpts)
   693  	if err != nil {
   694  		if except != nil {
   695  			if exceptVar != nil {
   696  				err := exceptVar.Set(err.(Exception))
   697  				if err != nil {
   698  					return fm.errorp(op, err)
   699  				}
   700  			}
   701  			err = except.Call(fm.fork("try except"), NoArgs, NoOpts)
   702  		}
   703  	} else {
   704  		if elseFn != nil {
   705  			err = elseFn.Call(fm.fork("try else"), NoArgs, NoOpts)
   706  		}
   707  	}
   708  	if finally != nil {
   709  		errFinally := finally.Call(fm.fork("try finally"), NoArgs, NoOpts)
   710  		if errFinally != nil {
   711  			// TODO: If err is not nil, this discards err. Use something similar
   712  			// to pipeline exception to expose both.
   713  			return fm.errorp(op, errFinally)
   714  		}
   715  	}
   716  	return fm.errorp(op, err)
   717  }
   718  
   719  func (cp *compiler) compileOneLValue(n *parse.Compound) lvalue {
   720  	if len(n.Indexings) != 1 {
   721  		cp.errorpf(n, "must be valid lvalue")
   722  	}
   723  	lvalues := cp.parseIndexingLValue(n.Indexings[0])
   724  	if lvalues.rest != -1 {
   725  		cp.errorpf(lvalues.lvalues[lvalues.rest], "rest variable not allowed")
   726  	}
   727  	if len(lvalues.lvalues) != 1 {
   728  		cp.errorpf(n, "must be exactly one lvalue")
   729  	}
   730  	return lvalues.lvalues[0]
   731  }
   732  
   733  // Executes a valuesOp that is known to yield a lambda and returns the lambda.
   734  // Returns nil if op is nil.
   735  func execLambdaOp(fm *Frame, op valuesOp) Callable {
   736  	if op == nil {
   737  		return nil
   738  	}
   739  	values, exc := op.exec(fm)
   740  	if exc != nil {
   741  		panic("must not be erroneous")
   742  	}
   743  	return values[0].(Callable)
   744  }