mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
101 lines
2.2 KiB
Go
101 lines
2.2 KiB
Go
package eval
|
|
|
|
import (
|
|
"src.elv.sh/pkg/diag"
|
|
"src.elv.sh/pkg/parse"
|
|
"src.elv.sh/pkg/parse/cmpd"
|
|
)
|
|
|
|
// Utilities for working with nodes.
|
|
|
|
func stringLiteralOrError(cp *compiler, n *parse.Compound, what string) string {
|
|
s, err := cmpd.StringLiteralOrError(n, what)
|
|
if err != nil {
|
|
cp.errorpf(n, "%v", err)
|
|
}
|
|
return s
|
|
}
|
|
|
|
type errorpfer interface {
|
|
errorpf(r diag.Ranger, fmt string, args ...any)
|
|
}
|
|
|
|
// argsWalker is used by builtin special forms to implement argument parsing.
|
|
type argsWalker struct {
|
|
cp errorpfer
|
|
form *parse.Form
|
|
idx int
|
|
}
|
|
|
|
func (cp *compiler) walkArgs(f *parse.Form) *argsWalker {
|
|
return &argsWalker{cp, f, 0}
|
|
}
|
|
|
|
func (aw *argsWalker) more() bool {
|
|
return aw.idx < len(aw.form.Args)
|
|
}
|
|
|
|
func (aw *argsWalker) peek() *parse.Compound {
|
|
if !aw.more() {
|
|
aw.cp.errorpf(aw.form, "need more arguments")
|
|
}
|
|
return aw.form.Args[aw.idx]
|
|
}
|
|
|
|
func (aw *argsWalker) next() *parse.Compound {
|
|
n := aw.peek()
|
|
aw.idx++
|
|
return n
|
|
}
|
|
|
|
func (aw *argsWalker) peekIs(text string) bool {
|
|
return aw.more() && parse.SourceText(aw.form.Args[aw.idx]) == text
|
|
}
|
|
|
|
// nextIs returns whether the next argument's source matches the given text. It
|
|
// also consumes the argument if it is.
|
|
func (aw *argsWalker) nextIs(text string) bool {
|
|
if aw.peekIs(text) {
|
|
aw.idx++
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// nextMustLambda fetches the next argument, raising an error if it is not a
|
|
// lambda.
|
|
func (aw *argsWalker) nextMustLambda(what string) *parse.Primary {
|
|
n := aw.next()
|
|
pn, ok := cmpd.Lambda(n)
|
|
if !ok {
|
|
aw.cp.errorpf(n, "%s must be lambda, found %s", what, cmpd.Shape(n))
|
|
}
|
|
return pn
|
|
}
|
|
|
|
// nextMustThunk fetches the next argument, raising an error if it is not a
|
|
// thunk.
|
|
func (aw *argsWalker) nextMustThunk(what string) *parse.Primary {
|
|
n := aw.nextMustLambda(what)
|
|
if len(n.Elements) > 0 {
|
|
aw.cp.errorpf(n, "%s must not have arguments", what)
|
|
}
|
|
if len(n.MapPairs) > 0 {
|
|
aw.cp.errorpf(n, "%s must not have options", what)
|
|
}
|
|
return n
|
|
}
|
|
|
|
func (aw *argsWalker) nextMustThunkIfAfter(leader string) *parse.Primary {
|
|
if aw.nextIs(leader) {
|
|
return aw.nextMustLambda(leader + " body")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (aw *argsWalker) mustEnd() {
|
|
if aw.more() {
|
|
aw.cp.errorpf(diag.Ranging{From: aw.form.Args[aw.idx].Range().From, To: aw.form.Range().To}, "too many arguments")
|
|
}
|
|
}
|