• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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