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 "strings" 18 19type Scope interface { 20 Get(name string) string 21 Set(name, value string) 22 Call(name string, args []string) []string 23 SetFunc(name string, f func([]string) []string) 24} 25 26type scope struct { 27 variables map[string]string 28 functions map[string]func([]string) []string 29 parent Scope 30} 31 32func (s *scope) Get(name string) string { 33 if val, ok := s.variables[name]; ok { 34 return val 35 } else if s.parent != nil { 36 return s.parent.Get(name) 37 } else if val, ok := builtinScope[name]; ok { 38 return val 39 } else { 40 return "<'" + name + "' unset>" 41 } 42} 43 44func (s *scope) Set(name, value string) { 45 s.variables[name] = value 46} 47 48func (s *scope) Call(name string, args []string) []string { 49 if f, ok := s.functions[name]; ok { 50 return f(args) 51 } 52 53 return []string{"<func:'" + name + "' unset>"} 54} 55 56func (s *scope) SetFunc(name string, f func([]string) []string) { 57 s.functions[name] = f 58} 59 60func NewScope(parent Scope) Scope { 61 return &scope{ 62 variables: make(map[string]string), 63 functions: make(map[string]func([]string) []string), 64 parent: parent, 65 } 66} 67 68var builtinScope map[string]string 69 70func init() { 71 builtinScope := make(map[string]string) 72 builtinScope[builtinDollar] = "$" 73} 74 75func (v Variable) EvalFunction(scope Scope) ([]string, bool) { 76 f := v.Name.SplitN(" \t", 2) 77 if len(f) > 1 && f[0].Const() { 78 fname := f[0].Value(nil) 79 if isFunctionName(fname) { 80 args := f[1].Split(",") 81 argVals := make([]string, len(args)) 82 for i, a := range args { 83 argVals[i] = a.Value(scope) 84 } 85 86 if fname == "call" { 87 return scope.Call(argVals[0], argVals[1:]), true 88 } else { 89 return []string{"UNSUPPORTED FUNCTION:" + fname + " " + strings.Join(argVals, " ")}, true 90 } 91 } 92 } 93 94 return []string{""}, false 95} 96 97func (v Variable) Value(scope Scope) string { 98 if ret, ok := v.EvalFunction(scope); ok { 99 if len(ret) > 1 { 100 panic("Expected a single value, but instead got a list") 101 } 102 return ret[0] 103 } 104 if scope == nil { 105 panic("Cannot take the value of a variable in a nil scope") 106 } 107 return scope.Get(v.Name.Value(scope)) 108} 109 110func toVariable(ms *MakeString) (Variable, bool) { 111 if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" { 112 return ms.Variables[0], true 113 } 114 return Variable{}, false 115} 116