github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/resolve.go (about) 1 package eval 2 3 import ( 4 "os" 5 "strings" 6 7 "github.com/u-root/u-root/cmds/core/elvish/eval/vars" 8 ) 9 10 // Resolution and iteration of variables and namespaces. 11 12 // EachVariableInTop calls the passed function for each variable name in 13 // namespace ns that can be found from the top context. 14 func (ev *evalerScopes) EachVariableInTop(ns string, f func(s string)) { 15 switch ns { 16 case "builtin": 17 for name := range ev.Builtin { 18 f(name) 19 } 20 case "": 21 for name := range ev.Global { 22 f(name) 23 } 24 for name := range ev.Builtin { 25 f(name) 26 } 27 case "e": 28 EachExternal(func(cmd string) { 29 f(cmd + FnSuffix) 30 }) 31 case "E": 32 for _, s := range os.Environ() { 33 if i := strings.IndexByte(s, '='); i > 0 { 34 f(s[:i]) 35 } 36 } 37 default: 38 segs := splitQName(ns + NsSuffix) 39 mod := ev.Global[segs[0]] 40 if mod == nil { 41 mod = ev.Builtin[segs[0]] 42 } 43 for _, seg := range segs[1:] { 44 if mod == nil { 45 return 46 } 47 mod = mod.Get().(Ns)[seg] 48 } 49 if mod != nil { 50 for name := range mod.Get().(Ns) { 51 f(name) 52 } 53 } 54 } 55 } 56 57 // EachNsInTop calls the passed function for each namespace that can be used 58 // from the top context. 59 func (ev *evalerScopes) EachNsInTop(f func(s string)) { 60 f("builtin") 61 f("e") 62 f("E") 63 64 for name := range ev.Global { 65 if strings.HasSuffix(name, NsSuffix) { 66 f(name[:len(name)-len(NsSuffix)]) 67 } 68 } 69 for name := range ev.Builtin { 70 if strings.HasSuffix(name, NsSuffix) { 71 f(name[:len(name)-len(NsSuffix)]) 72 } 73 } 74 } 75 76 // ResolveVar resolves a variable. When the variable cannot be found, nil is 77 // returned. 78 func (fm *Frame) ResolveVar(n, name string) vars.Var { 79 if n == "" { 80 return fm.resolveUnqualified(name) 81 } 82 83 // TODO: Let this function accept the fully qualified name. 84 segs := splitQName(n + ":" + name) 85 86 var ns Ns 87 88 switch segs[0] { 89 case "e:": 90 if len(segs) == 2 && strings.HasSuffix(segs[1], FnSuffix) { 91 return vars.NewRo(ExternalCmd{Name: segs[1][:len(segs[1])-len(FnSuffix)]}) 92 } 93 return nil 94 case "E:": 95 if len(segs) == 2 { 96 return vars.NewEnv(segs[1]) 97 } 98 return nil 99 case "local:": 100 ns = fm.local 101 case "up:": 102 ns = fm.up 103 case "builtin:": 104 ns = fm.Builtin 105 default: 106 v := fm.resolveUnqualified(segs[0]) 107 if v == nil { 108 return nil 109 } 110 ns = v.Get().(Ns) 111 } 112 113 for _, seg := range segs[1 : len(segs)-1] { 114 v := ns[seg] 115 if v == nil { 116 return nil 117 } 118 ns = v.Get().(Ns) 119 } 120 return ns[segs[len(segs)-1]] 121 } 122 123 func splitQName(qname string) []string { 124 i := 0 125 var segs []string 126 for i < len(qname) { 127 j := strings.IndexByte(qname[i:], ':') 128 if j == -1 { 129 segs = append(segs, qname[i:]) 130 break 131 } 132 segs = append(segs, qname[i:i+j+1]) 133 i += j + 1 134 } 135 return segs 136 } 137 138 func (fm *Frame) resolveUnqualified(name string) vars.Var { 139 if v, ok := fm.local[name]; ok { 140 return v 141 } 142 if v, ok := fm.up[name]; ok { 143 return v 144 } 145 return fm.Builtin[name] 146 }