github.com/elves/Elvish@v0.12.0/eval/args_walker.go (about)

     1  package eval
     2  
     3  import "github.com/elves/elvish/parse"
     4  
     5  type errorpfer interface {
     6  	errorpf(begin, end int, fmt string, args ...interface{})
     7  }
     8  
     9  // argsWalker is used by builtin special forms to implement argument parsing.
    10  type argsWalker struct {
    11  	cp   errorpfer
    12  	form *parse.Form
    13  	idx  int
    14  }
    15  
    16  func (cp *compiler) walkArgs(f *parse.Form) *argsWalker {
    17  	return &argsWalker{cp, f, 0}
    18  }
    19  
    20  func (aw *argsWalker) more() bool {
    21  	return aw.idx < len(aw.form.Args)
    22  }
    23  
    24  func (aw *argsWalker) peek() *parse.Compound {
    25  	if !aw.more() {
    26  		aw.cp.errorpf(aw.form.End(), aw.form.End(), "need more arguments")
    27  	}
    28  	return aw.form.Args[aw.idx]
    29  }
    30  
    31  func (aw *argsWalker) next() *parse.Compound {
    32  	n := aw.peek()
    33  	aw.idx++
    34  	return n
    35  }
    36  
    37  // nextIs returns whether the next argument's source matches the given text. It
    38  // also consumes the argument if it is.
    39  func (aw *argsWalker) nextIs(text string) bool {
    40  	if aw.more() && aw.form.Args[aw.idx].SourceText() == text {
    41  		aw.idx++
    42  		return true
    43  	}
    44  	return false
    45  }
    46  
    47  // nextMustLambda fetches the next argument, raising an error if it is not a
    48  // lambda.
    49  func (aw *argsWalker) nextMustLambda() *parse.Primary {
    50  	n := aw.next()
    51  	if len(n.Indexings) != 1 {
    52  		aw.cp.errorpf(n.Begin(), n.End(), "must be lambda")
    53  	}
    54  	if len(n.Indexings[0].Indicies) != 0 {
    55  		aw.cp.errorpf(n.Begin(), n.End(), "must be lambda")
    56  	}
    57  	pn := n.Indexings[0].Head
    58  	if pn.Type != parse.Lambda {
    59  		aw.cp.errorpf(n.Begin(), n.End(), "must be lambda")
    60  	}
    61  	return pn
    62  }
    63  
    64  func (aw *argsWalker) nextMustLambdaIfAfter(leader string) *parse.Primary {
    65  	if aw.nextIs(leader) {
    66  		return aw.nextMustLambda()
    67  	}
    68  	return nil
    69  }
    70  
    71  func (aw *argsWalker) mustEnd() {
    72  	if aw.more() {
    73  		aw.cp.errorpf(aw.form.Args[aw.idx].Begin(), aw.form.End(), "too many arguments")
    74  	}
    75  }