src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/purely_eval.go (about) 1 package eval 2 3 import ( 4 "strings" 5 6 "src.elv.sh/pkg/parse" 7 ) 8 9 func (ev *Evaler) PurelyEvalCompound(cn *parse.Compound) (string, bool) { 10 return ev.PurelyEvalPartialCompound(cn, -1) 11 } 12 13 func (ev *Evaler) PurelyEvalPartialCompound(cn *parse.Compound, upto int) (string, bool) { 14 tilde := false 15 head := "" 16 for _, in := range cn.Indexings { 17 if len(in.Indices) > 0 { 18 return "", false 19 } 20 if upto >= 0 && in.To > upto { 21 break 22 } 23 switch in.Head.Type { 24 case parse.Tilde: 25 tilde = true 26 case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted: 27 head += in.Head.Value 28 case parse.Variable: 29 if ev == nil { 30 return "", false 31 } 32 v := ev.PurelyEvalPrimary(in.Head) 33 if s, ok := v.(string); ok { 34 head += s 35 } else { 36 return "", false 37 } 38 default: 39 return "", false 40 } 41 } 42 if tilde { 43 i := strings.Index(head, "/") 44 if i == -1 { 45 i = len(head) 46 } 47 uname := head[:i] 48 home, err := getHome(uname) 49 if err != nil { 50 return "", false 51 } 52 head = home + head[i:] 53 } 54 return head, true 55 } 56 57 // PurelyEvalPrimary evaluates a primary node without causing any side effects. 58 // If this cannot be done, it returns nil. 59 // 60 // Currently, only string literals and variables with no @ can be evaluated. 61 func (ev *Evaler) PurelyEvalPrimary(pn *parse.Primary) any { 62 switch pn.Type { 63 case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted: 64 return pn.Value 65 case parse.Variable: 66 sigil, qname := SplitSigil(pn.Value) 67 if sigil != "" { 68 return nil 69 } 70 fm := &Frame{Evaler: ev, local: ev.Global(), up: new(Ns)} 71 ref := resolveVarRef(fm, qname, nil) 72 if ref != nil { 73 variable := deref(fm, ref) 74 if variable == nil { 75 return nil 76 } 77 return variable.Get() 78 } 79 } 80 return nil 81 }