blob: 167e470b4a2611622a26228900cc565c255ee046 [file] [log] [blame]
Colin Crossd00350c2017-11-17 10:55:38 -08001// 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
Colin Cross3f40fa42015-01-30 17:27:36 -080015package parser
16
Jeff Gastonf3ccfa92017-08-23 17:03:42 -070017import (
18 "strings"
19)
Colin Cross3f40fa42015-01-30 17:27:36 -080020
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 "<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)
Dan Willemsen43398532018-02-21 02:10:29 -080074 builtinScope[builtinDollar] = "$"
Colin Cross3f40fa42015-01-30 17:27:36 -080075}
76
Colin Cross16daa922015-04-03 16:51:45 -070077func (v Variable) EvalFunction(scope Scope) (string, bool) {
Colin Cross3f40fa42015-01-30 17:27:36 -080078 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" {
Colin Cross16daa922015-04-03 16:51:45 -070089 return scope.Call(argVals[0], argVals[1:]), true
Colin Cross3f40fa42015-01-30 17:27:36 -080090 } else {
Colin Cross16daa922015-04-03 16:51:45 -070091 return "__builtin_func:" + fname + " " + strings.Join(argVals, " "), true
Colin Cross3f40fa42015-01-30 17:27:36 -080092 }
93 }
94 }
95
Colin Cross16daa922015-04-03 16:51:45 -070096 return "", false
97}
98
99func (v Variable) Value(scope Scope) string {
100 if ret, ok := v.EvalFunction(scope); ok {
101 return ret
102 }
Jeff Gastonf3ccfa92017-08-23 17:03:42 -0700103 if scope == nil {
104 panic("Cannot take the value of a variable in a nil scope")
105 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800106 return scope.Get(v.Name.Value(scope))
107}
108
109func toVariable(ms *MakeString) (Variable, bool) {
110 if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
111 return ms.Variables[0], true
112 }
113 return Variable{}, false
114}