Home | History | Annotate | Download | only in parser
      1 package parser
      2 
      3 import "strings"
      4 
      5 type 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 
     12 type scope struct {
     13 	variables map[string]string
     14 	functions map[string]func([]string) string
     15 	parent    Scope
     16 }
     17 
     18 func (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 
     30 func (s *scope) Set(name, value string) {
     31 	s.variables[name] = value
     32 }
     33 
     34 func (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 
     42 func (s *scope) SetFunc(name string, f func([]string) string) {
     43 	s.functions[name] = f
     44 }
     45 
     46 func 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 
     54 var builtinScope map[string]string
     55 
     56 func init() {
     57 	builtinScope := make(map[string]string)
     58 	builtinScope["__builtin_dollar"] = "$"
     59 }
     60 
     61 func (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 
     83 func (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 
     90 func 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