github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/purely_eval.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "strings" 6 7 "github.com/u-root/u-root/cmds/core/elvish/parse" 8 "github.com/u-root/u-root/cmds/core/elvish/util" 9 ) 10 11 var ErrImpure = errors.New("expression is impure") 12 13 func PurelyEvalCompound(cn *parse.Compound) (string, error) { 14 return (*Evaler)(nil).PurelyEvalCompound(cn) 15 } 16 17 func (ev *Evaler) PurelyEvalCompound(cn *parse.Compound) (string, error) { 18 return ev.PurelyEvalPartialCompound(cn, nil) 19 } 20 21 func (ev *Evaler) PurelyEvalPartialCompound(cn *parse.Compound, upto *parse.Indexing) (string, error) { 22 tilde := false 23 head := "" 24 for _, in := range cn.Indexings { 25 if len(in.Indicies) > 0 { 26 return "", ErrImpure 27 } 28 switch in.Head.Type { 29 case parse.Tilde: 30 tilde = true 31 case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted: 32 head += in.Head.Value 33 case parse.Variable: 34 if ev == nil { 35 return "", ErrImpure 36 } 37 v := ev.PurelyEvalPrimary(in.Head) 38 if s, ok := v.(string); ok { 39 head += s 40 } else { 41 return "", ErrImpure 42 } 43 default: 44 return "", ErrImpure 45 } 46 47 if in == upto { 48 break 49 } 50 } 51 if tilde { 52 i := strings.Index(head, "/") 53 if i == -1 { 54 i = len(head) 55 } 56 uname := head[:i] 57 home, err := util.GetHome(uname) 58 if err != nil { 59 return "", err 60 } 61 head = home + head[i:] 62 } 63 return head, nil 64 } 65 66 // PurelyEvalPrimary evaluates a primary node without causing any side effects. 67 // If this cannot be done, it returns nil. 68 // 69 // Currently, only string literals and variables with no @ can be evaluated. 70 func (ev *Evaler) PurelyEvalPrimary(pn *parse.Primary) interface{} { 71 switch pn.Type { 72 case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted: 73 return pn.Value 74 case parse.Variable: 75 explode, ns, name := ParseVariableRef(pn.Value) 76 if explode { 77 return nil 78 } 79 ec := NewTopFrame(ev, NewInternalSource("[purely eval]"), nil) 80 variable := ec.ResolveVar(ns, name) 81 if variable != nil { 82 return variable.Get() 83 } 84 } 85 return nil 86 }