2017-12-18 09:32:04 +08:00
|
|
|
package eval
|
2017-05-30 06:39:40 +08:00
|
|
|
|
|
|
|
import (
|
2017-12-18 09:23:28 +08:00
|
|
|
"errors"
|
2017-05-30 06:39:40 +08:00
|
|
|
"strings"
|
|
|
|
|
2020-09-03 12:27:18 +08:00
|
|
|
"github.com/elves/elvish/pkg/fsutil"
|
2019-12-24 04:00:59 +08:00
|
|
|
"github.com/elves/elvish/pkg/parse"
|
2017-05-30 06:39:40 +08:00
|
|
|
)
|
|
|
|
|
2017-12-18 09:23:28 +08:00
|
|
|
var ErrImpure = errors.New("expression is impure")
|
|
|
|
|
2017-12-18 09:32:04 +08:00
|
|
|
func (ev *Evaler) PurelyEvalCompound(cn *parse.Compound) (string, error) {
|
2020-03-31 12:13:00 +08:00
|
|
|
return ev.PurelyEvalPartialCompound(cn, -1)
|
2017-12-18 09:23:28 +08:00
|
|
|
}
|
|
|
|
|
2020-03-31 12:13:00 +08:00
|
|
|
func (ev *Evaler) PurelyEvalPartialCompound(cn *parse.Compound, upto int) (string, error) {
|
2017-05-30 06:39:40 +08:00
|
|
|
tilde := false
|
|
|
|
head := ""
|
|
|
|
for _, in := range cn.Indexings {
|
|
|
|
if len(in.Indicies) > 0 {
|
2017-12-18 09:23:28 +08:00
|
|
|
return "", ErrImpure
|
2017-05-30 06:39:40 +08:00
|
|
|
}
|
2020-03-31 12:13:00 +08:00
|
|
|
if upto >= 0 && in.To > upto {
|
|
|
|
break
|
|
|
|
}
|
2017-05-30 06:39:40 +08:00
|
|
|
switch in.Head.Type {
|
|
|
|
case parse.Tilde:
|
|
|
|
tilde = true
|
|
|
|
case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
|
|
|
|
head += in.Head.Value
|
2017-07-20 18:45:00 +08:00
|
|
|
case parse.Variable:
|
|
|
|
if ev == nil {
|
2017-12-18 09:23:28 +08:00
|
|
|
return "", ErrImpure
|
2017-07-20 18:45:00 +08:00
|
|
|
}
|
2017-12-18 09:32:04 +08:00
|
|
|
v := ev.PurelyEvalPrimary(in.Head)
|
2018-01-25 09:40:15 +08:00
|
|
|
if s, ok := v.(string); ok {
|
|
|
|
head += s
|
2017-07-20 18:45:00 +08:00
|
|
|
} else {
|
2017-12-18 09:23:28 +08:00
|
|
|
return "", ErrImpure
|
2017-07-20 18:45:00 +08:00
|
|
|
}
|
2017-05-30 06:39:40 +08:00
|
|
|
default:
|
2017-12-18 09:23:28 +08:00
|
|
|
return "", ErrImpure
|
2017-05-30 06:39:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if tilde {
|
|
|
|
i := strings.Index(head, "/")
|
|
|
|
if i == -1 {
|
|
|
|
i = len(head)
|
|
|
|
}
|
|
|
|
uname := head[:i]
|
2020-09-03 12:27:18 +08:00
|
|
|
home, err := fsutil.GetHome(uname)
|
2017-05-30 06:39:40 +08:00
|
|
|
if err != nil {
|
2017-12-18 09:23:28 +08:00
|
|
|
return "", err
|
2017-05-30 06:39:40 +08:00
|
|
|
}
|
|
|
|
head = home + head[i:]
|
|
|
|
}
|
2017-12-18 09:23:28 +08:00
|
|
|
return head, nil
|
2017-05-30 06:39:40 +08:00
|
|
|
}
|
2017-07-20 18:45:00 +08:00
|
|
|
|
|
|
|
// PurelyEvalPrimary evaluates a primary node without causing any side effects.
|
|
|
|
// If this cannot be done, it returns nil.
|
|
|
|
//
|
|
|
|
// Currently, only string literals and variables with no @ can be evaluated.
|
2018-01-30 01:39:41 +08:00
|
|
|
func (ev *Evaler) PurelyEvalPrimary(pn *parse.Primary) interface{} {
|
2017-07-20 18:45:00 +08:00
|
|
|
switch pn.Type {
|
|
|
|
case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
|
2018-01-25 09:40:15 +08:00
|
|
|
return pn.Value
|
2017-07-20 18:45:00 +08:00
|
|
|
case parse.Variable:
|
2020-12-26 06:31:52 +08:00
|
|
|
sigil, qname := SplitSigil(pn.Value)
|
2019-10-23 05:49:32 +08:00
|
|
|
if sigil != "" {
|
2017-07-20 18:45:00 +08:00
|
|
|
return nil
|
|
|
|
}
|
2021-01-05 07:54:13 +08:00
|
|
|
fm := &Frame{Evaler: ev, local: ev.Global(), up: new(Ns)}
|
2020-12-25 01:39:51 +08:00
|
|
|
ref := resolveVarRef(fm, qname, nil)
|
|
|
|
if ref != nil {
|
2021-01-09 23:54:12 +08:00
|
|
|
variable := deref(fm, ref)
|
|
|
|
if variable == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return variable.Get()
|
2017-10-01 10:47:25 +08:00
|
|
|
}
|
2017-07-20 18:45:00 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|