github.com/kolbycrouch/elvish@v0.14.1-0.20210614162631-215b9ac1c423/pkg/eval/node_utils.go (about)

     1  package eval
     2  
     3  import (
     4  	"src.elv.sh/pkg/diag"
     5  	"src.elv.sh/pkg/parse"
     6  	"src.elv.sh/pkg/parse/cmpd"
     7  )
     8  
     9  // Utilities for working with nodes.
    10  
    11  func stringLiteralOrError(cp *compiler, n *parse.Compound, what string) string {
    12  	s, err := cmpd.StringLiteralOrError(n, what)
    13  	if err != nil {
    14  		cp.errorpf(n, "%v", err)
    15  	}
    16  	return s
    17  }
    18  
    19  type errorpfer interface {
    20  	errorpf(r diag.Ranger, fmt string, args ...interface{})
    21  }
    22  
    23  // argsWalker is used by builtin special forms to implement argument parsing.
    24  type argsWalker struct {
    25  	cp   errorpfer
    26  	form *parse.Form
    27  	idx  int
    28  }
    29  
    30  func (cp *compiler) walkArgs(f *parse.Form) *argsWalker {
    31  	return &argsWalker{cp, f, 0}
    32  }
    33  
    34  func (aw *argsWalker) more() bool {
    35  	return aw.idx < len(aw.form.Args)
    36  }
    37  
    38  func (aw *argsWalker) peek() *parse.Compound {
    39  	if !aw.more() {
    40  		aw.cp.errorpf(aw.form, "need more arguments")
    41  	}
    42  	return aw.form.Args[aw.idx]
    43  }
    44  
    45  func (aw *argsWalker) next() *parse.Compound {
    46  	n := aw.peek()
    47  	aw.idx++
    48  	return n
    49  }
    50  
    51  // nextIs returns whether the next argument's source matches the given text. It
    52  // also consumes the argument if it is.
    53  func (aw *argsWalker) nextIs(text string) bool {
    54  	if aw.more() && parse.SourceText(aw.form.Args[aw.idx]) == text {
    55  		aw.idx++
    56  		return true
    57  	}
    58  	return false
    59  }
    60  
    61  // nextMustLambda fetches the next argument, raising an error if it is not a
    62  // lambda.
    63  func (aw *argsWalker) nextMustLambda(what string) *parse.Primary {
    64  	n := aw.next()
    65  	pn, ok := cmpd.Lambda(n)
    66  	if !ok {
    67  		aw.cp.errorpf(n, "%s must be lambda, found %s", what, cmpd.Shape(n))
    68  	}
    69  	return pn
    70  }
    71  
    72  func (aw *argsWalker) nextMustLambdaIfAfter(leader string) *parse.Primary {
    73  	if aw.nextIs(leader) {
    74  		return aw.nextMustLambda(leader + " body")
    75  	}
    76  	return nil
    77  }
    78  
    79  func (aw *argsWalker) mustEnd() {
    80  	if aw.more() {
    81  		aw.cp.errorpf(diag.Ranging{From: aw.form.Args[aw.idx].Range().From, To: aw.form.Range().To}, "too many arguments")
    82  	}
    83  }