github.com/elves/elvish@v0.15.0/pkg/eval/args_walker.go (about)

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