1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package parser 16 17import ( 18 "strings" 19) 20 21type Scope interface { 22 Get(name string) string 23 Set(name, value string) 24 Call(name string, args []string) []string 25 SetFunc(name string, f func([]string) []string) 26} 27 28type scope struct { 29 variables map[string]string 30 functions map[string]func([]string) []string 31 parent Scope 32} 33 34func (s *scope) Get(name string) string { 35 if val, ok := s.variables[name]; ok { 36 return val 37 } else if s.parent != nil { 38 return s.parent.Get(name) 39 } else if val, ok := builtinScope[name]; ok { 40 return val 41 } else { 42 return "<'" + name + "' unset>" 43 } 44} 45 46func (s *scope) Set(name, value string) { 47 s.variables[name] = value 48} 49 50func (s *scope) Call(name string, args []string) []string { 51 if f, ok := s.functions[name]; ok { 52 return f(args) 53 } 54 55 return []string{"<func:'" + name + "' unset>"} 56} 57 58func (s *scope) SetFunc(name string, f func([]string) []string) { 59 s.functions[name] = f 60} 61 62func NewScope(parent Scope) Scope { 63 return &scope{ 64 variables: make(map[string]string), 65 functions: make(map[string]func([]string) []string), 66 parent: parent, 67 } 68} 69 70var builtinScope map[string]string 71 72func init() { 73 builtinScope := make(map[string]string) 74 builtinScope[builtinDollar] = "$" 75} 76 77func (v Variable) EvalFunction(scope Scope) ([]string, bool) { 78 f := v.Name.SplitN(" \t", 2) 79 if len(f) > 1 && f[0].Const() { 80 fname := f[0].Value(nil) 81 if isFunctionName(fname) { 82 args := f[1].Split(",") 83 argVals := make([]string, len(args)) 84 for i, a := range args { 85 argVals[i] = a.Value(scope) 86 } 87 88 if fname == "call" { 89 return scope.Call(argVals[0], argVals[1:]), true 90 } else { 91 return []string{"__builtin_func:" + fname + " " + strings.Join(argVals, " ")}, true 92 } 93 } 94 } 95 96 return []string{""}, false 97} 98 99func (v Variable) Value(scope Scope) string { 100 if ret, ok := v.EvalFunction(scope); ok { 101 if len(ret) > 1 { 102 panic("Expected a single value, but instead got a list") 103 } 104 return ret[0] 105 } 106 if scope == nil { 107 panic("Cannot take the value of a variable in a nil scope") 108 } 109 return scope.Get(v.Name.Value(scope)) 110} 111 112func toVariable(ms *MakeString) (Variable, bool) { 113 if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" { 114 return ms.Variables[0], true 115 } 116 return Variable{}, false 117} 118