1package parser 2 3import "strings" 4 5type Scope interface { 6 Get(name string) string 7 Set(name, value string) 8 Call(name string, args []string) string 9 SetFunc(name string, f func([]string) string) 10} 11 12type scope struct { 13 variables map[string]string 14 functions map[string]func([]string) string 15 parent Scope 16} 17 18func (s *scope) Get(name string) string { 19 if val, ok := s.variables[name]; ok { 20 return val 21 } else if s.parent != nil { 22 return s.parent.Get(name) 23 } else if val, ok := builtinScope[name]; ok { 24 return val 25 } else { 26 return "<'" + name + "' unset>" 27 } 28} 29 30func (s *scope) Set(name, value string) { 31 s.variables[name] = value 32} 33 34func (s *scope) Call(name string, args []string) string { 35 if f, ok := s.functions[name]; ok { 36 return f(args) 37 } 38 39 return "<func:'" + name + "' unset>" 40} 41 42func (s *scope) SetFunc(name string, f func([]string) string) { 43 s.functions[name] = f 44} 45 46func NewScope(parent Scope) Scope { 47 return &scope{ 48 variables: make(map[string]string), 49 functions: make(map[string]func([]string) string), 50 parent: parent, 51 } 52} 53 54var builtinScope map[string]string 55 56func init() { 57 builtinScope := make(map[string]string) 58 builtinScope["__builtin_dollar"] = "$" 59} 60 61func (v Variable) EvalFunction(scope Scope) (string, bool) { 62 f := v.Name.SplitN(" \t", 2) 63 if len(f) > 1 && f[0].Const() { 64 fname := f[0].Value(nil) 65 if isFunctionName(fname) { 66 args := f[1].Split(",") 67 argVals := make([]string, len(args)) 68 for i, a := range args { 69 argVals[i] = a.Value(scope) 70 } 71 72 if fname == "call" { 73 return scope.Call(argVals[0], argVals[1:]), true 74 } else { 75 return "__builtin_func:" + fname + " " + strings.Join(argVals, " "), true 76 } 77 } 78 } 79 80 return "", false 81} 82 83func (v Variable) Value(scope Scope) string { 84 if ret, ok := v.EvalFunction(scope); ok { 85 return ret 86 } 87 return scope.Get(v.Name.Value(scope)) 88} 89 90func toVariable(ms *MakeString) (Variable, bool) { 91 if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" { 92 return ms.Variables[0], true 93 } 94 return Variable{}, false 95} 96