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  }