xref: /aosp_15_r20/build/blueprint/scope.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2014 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"fmt"
19*1fa6dee9SAndroid Build Coastguard Worker	"strings"
20*1fa6dee9SAndroid Build Coastguard Worker	"unicode"
21*1fa6dee9SAndroid Build Coastguard Worker	"unicode/utf8"
22*1fa6dee9SAndroid Build Coastguard Worker)
23*1fa6dee9SAndroid Build Coastguard Worker
24*1fa6dee9SAndroid Build Coastguard Worker// A Variable represents a global Ninja variable definition that will be written
25*1fa6dee9SAndroid Build Coastguard Worker// to the output .ninja file.  A variable may contain references to other global
26*1fa6dee9SAndroid Build Coastguard Worker// Ninja variables, but circular variable references are not allowed.
27*1fa6dee9SAndroid Build Coastguard Workertype Variable interface {
28*1fa6dee9SAndroid Build Coastguard Worker	packageContext() *packageContext
29*1fa6dee9SAndroid Build Coastguard Worker	name() string                                        // "foo"
30*1fa6dee9SAndroid Build Coastguard Worker	fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
31*1fa6dee9SAndroid Build Coastguard Worker	value(ctx VariableFuncContext, config interface{}) (*ninjaString, error)
32*1fa6dee9SAndroid Build Coastguard Worker	String() string
33*1fa6dee9SAndroid Build Coastguard Worker}
34*1fa6dee9SAndroid Build Coastguard Worker
35*1fa6dee9SAndroid Build Coastguard Worker// A Pool represents a Ninja pool that will be written to the output .ninja
36*1fa6dee9SAndroid Build Coastguard Worker// file.
37*1fa6dee9SAndroid Build Coastguard Workertype Pool interface {
38*1fa6dee9SAndroid Build Coastguard Worker	packageContext() *packageContext
39*1fa6dee9SAndroid Build Coastguard Worker	name() string                                        // "foo"
40*1fa6dee9SAndroid Build Coastguard Worker	fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
41*1fa6dee9SAndroid Build Coastguard Worker	def(config interface{}) (*poolDef, error)
42*1fa6dee9SAndroid Build Coastguard Worker	String() string
43*1fa6dee9SAndroid Build Coastguard Worker}
44*1fa6dee9SAndroid Build Coastguard Worker
45*1fa6dee9SAndroid Build Coastguard Worker// A Rule represents a Ninja build rule that will be written to the output
46*1fa6dee9SAndroid Build Coastguard Worker// .ninja file.
47*1fa6dee9SAndroid Build Coastguard Workertype Rule interface {
48*1fa6dee9SAndroid Build Coastguard Worker	packageContext() *packageContext
49*1fa6dee9SAndroid Build Coastguard Worker	name() string                                        // "foo"
50*1fa6dee9SAndroid Build Coastguard Worker	fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo"
51*1fa6dee9SAndroid Build Coastguard Worker	def(config interface{}) (*ruleDef, error)
52*1fa6dee9SAndroid Build Coastguard Worker	scope() *basicScope
53*1fa6dee9SAndroid Build Coastguard Worker	isArg(argName string) bool
54*1fa6dee9SAndroid Build Coastguard Worker	String() string
55*1fa6dee9SAndroid Build Coastguard Worker}
56*1fa6dee9SAndroid Build Coastguard Worker
57*1fa6dee9SAndroid Build Coastguard Workertype basicScope struct {
58*1fa6dee9SAndroid Build Coastguard Worker	parent    *basicScope
59*1fa6dee9SAndroid Build Coastguard Worker	variables map[string]Variable
60*1fa6dee9SAndroid Build Coastguard Worker	pools     map[string]Pool
61*1fa6dee9SAndroid Build Coastguard Worker	rules     map[string]Rule
62*1fa6dee9SAndroid Build Coastguard Worker	imports   map[string]*basicScope
63*1fa6dee9SAndroid Build Coastguard Worker}
64*1fa6dee9SAndroid Build Coastguard Worker
65*1fa6dee9SAndroid Build Coastguard Workerfunc newScope(parent *basicScope) *basicScope {
66*1fa6dee9SAndroid Build Coastguard Worker	return &basicScope{
67*1fa6dee9SAndroid Build Coastguard Worker		parent:    parent,
68*1fa6dee9SAndroid Build Coastguard Worker		variables: make(map[string]Variable),
69*1fa6dee9SAndroid Build Coastguard Worker		pools:     make(map[string]Pool),
70*1fa6dee9SAndroid Build Coastguard Worker		rules:     make(map[string]Rule),
71*1fa6dee9SAndroid Build Coastguard Worker		imports:   make(map[string]*basicScope),
72*1fa6dee9SAndroid Build Coastguard Worker	}
73*1fa6dee9SAndroid Build Coastguard Worker}
74*1fa6dee9SAndroid Build Coastguard Worker
75*1fa6dee9SAndroid Build Coastguard Workerfunc makeRuleScope(parent *basicScope, argNames map[string]bool) *basicScope {
76*1fa6dee9SAndroid Build Coastguard Worker	scope := newScope(parent)
77*1fa6dee9SAndroid Build Coastguard Worker	for argName := range argNames {
78*1fa6dee9SAndroid Build Coastguard Worker		_, err := scope.LookupVariable(argName)
79*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
80*1fa6dee9SAndroid Build Coastguard Worker			arg := &argVariable{argName}
81*1fa6dee9SAndroid Build Coastguard Worker			err = scope.AddVariable(arg)
82*1fa6dee9SAndroid Build Coastguard Worker			if err != nil {
83*1fa6dee9SAndroid Build Coastguard Worker				// This should not happen.  We should have already checked that
84*1fa6dee9SAndroid Build Coastguard Worker				// the name is valid and that the scope doesn't have a variable
85*1fa6dee9SAndroid Build Coastguard Worker				// with this name.
86*1fa6dee9SAndroid Build Coastguard Worker				panic(err)
87*1fa6dee9SAndroid Build Coastguard Worker			}
88*1fa6dee9SAndroid Build Coastguard Worker		}
89*1fa6dee9SAndroid Build Coastguard Worker	}
90*1fa6dee9SAndroid Build Coastguard Worker
91*1fa6dee9SAndroid Build Coastguard Worker	// We treat built-in variables like arguments for the purpose of this scope.
92*1fa6dee9SAndroid Build Coastguard Worker	for _, builtin := range builtinRuleArgs {
93*1fa6dee9SAndroid Build Coastguard Worker		arg := &argVariable{builtin}
94*1fa6dee9SAndroid Build Coastguard Worker		err := scope.AddVariable(arg)
95*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
96*1fa6dee9SAndroid Build Coastguard Worker			panic(err)
97*1fa6dee9SAndroid Build Coastguard Worker		}
98*1fa6dee9SAndroid Build Coastguard Worker	}
99*1fa6dee9SAndroid Build Coastguard Worker
100*1fa6dee9SAndroid Build Coastguard Worker	return scope
101*1fa6dee9SAndroid Build Coastguard Worker}
102*1fa6dee9SAndroid Build Coastguard Worker
103*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) LookupVariable(name string) (Variable, error) {
104*1fa6dee9SAndroid Build Coastguard Worker	dotIndex := strings.IndexRune(name, '.')
105*1fa6dee9SAndroid Build Coastguard Worker	if dotIndex >= 0 {
106*1fa6dee9SAndroid Build Coastguard Worker		// The variable name looks like "pkg.var"
107*1fa6dee9SAndroid Build Coastguard Worker		if dotIndex+1 == len(name) {
108*1fa6dee9SAndroid Build Coastguard Worker			return nil, fmt.Errorf("variable name %q ends with a '.'", name)
109*1fa6dee9SAndroid Build Coastguard Worker		}
110*1fa6dee9SAndroid Build Coastguard Worker		if strings.ContainsRune(name[dotIndex+1:], '.') {
111*1fa6dee9SAndroid Build Coastguard Worker			return nil, fmt.Errorf("variable name %q contains multiple '.' "+
112*1fa6dee9SAndroid Build Coastguard Worker				"characters", name)
113*1fa6dee9SAndroid Build Coastguard Worker		}
114*1fa6dee9SAndroid Build Coastguard Worker
115*1fa6dee9SAndroid Build Coastguard Worker		pkgName := name[:dotIndex]
116*1fa6dee9SAndroid Build Coastguard Worker		varName := name[dotIndex+1:]
117*1fa6dee9SAndroid Build Coastguard Worker
118*1fa6dee9SAndroid Build Coastguard Worker		first, _ := utf8.DecodeRuneInString(varName)
119*1fa6dee9SAndroid Build Coastguard Worker		if !unicode.IsUpper(first) {
120*1fa6dee9SAndroid Build Coastguard Worker			return nil, fmt.Errorf("cannot refer to unexported name %q", name)
121*1fa6dee9SAndroid Build Coastguard Worker		}
122*1fa6dee9SAndroid Build Coastguard Worker
123*1fa6dee9SAndroid Build Coastguard Worker		importedScope, err := s.lookupImportedScope(pkgName)
124*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
125*1fa6dee9SAndroid Build Coastguard Worker			return nil, err
126*1fa6dee9SAndroid Build Coastguard Worker		}
127*1fa6dee9SAndroid Build Coastguard Worker
128*1fa6dee9SAndroid Build Coastguard Worker		v, ok := importedScope.variables[varName]
129*1fa6dee9SAndroid Build Coastguard Worker		if !ok {
130*1fa6dee9SAndroid Build Coastguard Worker			return nil, fmt.Errorf("package %q does not contain variable %q",
131*1fa6dee9SAndroid Build Coastguard Worker				pkgName, varName)
132*1fa6dee9SAndroid Build Coastguard Worker		}
133*1fa6dee9SAndroid Build Coastguard Worker
134*1fa6dee9SAndroid Build Coastguard Worker		return v, nil
135*1fa6dee9SAndroid Build Coastguard Worker	} else {
136*1fa6dee9SAndroid Build Coastguard Worker		// The variable name has no package part; just "var"
137*1fa6dee9SAndroid Build Coastguard Worker		for ; s != nil; s = s.parent {
138*1fa6dee9SAndroid Build Coastguard Worker			v, ok := s.variables[name]
139*1fa6dee9SAndroid Build Coastguard Worker			if ok {
140*1fa6dee9SAndroid Build Coastguard Worker				return v, nil
141*1fa6dee9SAndroid Build Coastguard Worker			}
142*1fa6dee9SAndroid Build Coastguard Worker		}
143*1fa6dee9SAndroid Build Coastguard Worker		return nil, fmt.Errorf("undefined variable %q", name)
144*1fa6dee9SAndroid Build Coastguard Worker	}
145*1fa6dee9SAndroid Build Coastguard Worker}
146*1fa6dee9SAndroid Build Coastguard Worker
147*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) IsRuleVisible(rule Rule) bool {
148*1fa6dee9SAndroid Build Coastguard Worker	_, isBuiltin := rule.(*builtinRule)
149*1fa6dee9SAndroid Build Coastguard Worker	if isBuiltin {
150*1fa6dee9SAndroid Build Coastguard Worker		return true
151*1fa6dee9SAndroid Build Coastguard Worker	}
152*1fa6dee9SAndroid Build Coastguard Worker
153*1fa6dee9SAndroid Build Coastguard Worker	name := rule.name()
154*1fa6dee9SAndroid Build Coastguard Worker
155*1fa6dee9SAndroid Build Coastguard Worker	for s != nil {
156*1fa6dee9SAndroid Build Coastguard Worker		if s.rules[name] == rule {
157*1fa6dee9SAndroid Build Coastguard Worker			return true
158*1fa6dee9SAndroid Build Coastguard Worker		}
159*1fa6dee9SAndroid Build Coastguard Worker
160*1fa6dee9SAndroid Build Coastguard Worker		for _, import_ := range s.imports {
161*1fa6dee9SAndroid Build Coastguard Worker			if import_.rules[name] == rule {
162*1fa6dee9SAndroid Build Coastguard Worker				return true
163*1fa6dee9SAndroid Build Coastguard Worker			}
164*1fa6dee9SAndroid Build Coastguard Worker		}
165*1fa6dee9SAndroid Build Coastguard Worker
166*1fa6dee9SAndroid Build Coastguard Worker		s = s.parent
167*1fa6dee9SAndroid Build Coastguard Worker	}
168*1fa6dee9SAndroid Build Coastguard Worker
169*1fa6dee9SAndroid Build Coastguard Worker	return false
170*1fa6dee9SAndroid Build Coastguard Worker}
171*1fa6dee9SAndroid Build Coastguard Worker
172*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) IsPoolVisible(pool Pool) bool {
173*1fa6dee9SAndroid Build Coastguard Worker	_, isBuiltin := pool.(*builtinPool)
174*1fa6dee9SAndroid Build Coastguard Worker	if isBuiltin {
175*1fa6dee9SAndroid Build Coastguard Worker		return true
176*1fa6dee9SAndroid Build Coastguard Worker	}
177*1fa6dee9SAndroid Build Coastguard Worker
178*1fa6dee9SAndroid Build Coastguard Worker	name := pool.name()
179*1fa6dee9SAndroid Build Coastguard Worker
180*1fa6dee9SAndroid Build Coastguard Worker	for s != nil {
181*1fa6dee9SAndroid Build Coastguard Worker		if s.pools[name] == pool {
182*1fa6dee9SAndroid Build Coastguard Worker			return true
183*1fa6dee9SAndroid Build Coastguard Worker		}
184*1fa6dee9SAndroid Build Coastguard Worker
185*1fa6dee9SAndroid Build Coastguard Worker		for _, import_ := range s.imports {
186*1fa6dee9SAndroid Build Coastguard Worker			if import_.pools[name] == pool {
187*1fa6dee9SAndroid Build Coastguard Worker				return true
188*1fa6dee9SAndroid Build Coastguard Worker			}
189*1fa6dee9SAndroid Build Coastguard Worker		}
190*1fa6dee9SAndroid Build Coastguard Worker
191*1fa6dee9SAndroid Build Coastguard Worker		s = s.parent
192*1fa6dee9SAndroid Build Coastguard Worker	}
193*1fa6dee9SAndroid Build Coastguard Worker
194*1fa6dee9SAndroid Build Coastguard Worker	return false
195*1fa6dee9SAndroid Build Coastguard Worker}
196*1fa6dee9SAndroid Build Coastguard Worker
197*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) lookupImportedScope(pkgName string) (*basicScope, error) {
198*1fa6dee9SAndroid Build Coastguard Worker	for ; s != nil; s = s.parent {
199*1fa6dee9SAndroid Build Coastguard Worker		importedScope, ok := s.imports[pkgName]
200*1fa6dee9SAndroid Build Coastguard Worker		if ok {
201*1fa6dee9SAndroid Build Coastguard Worker			return importedScope, nil
202*1fa6dee9SAndroid Build Coastguard Worker		}
203*1fa6dee9SAndroid Build Coastguard Worker	}
204*1fa6dee9SAndroid Build Coastguard Worker	return nil, fmt.Errorf("unknown imported package %q (missing call to "+
205*1fa6dee9SAndroid Build Coastguard Worker		"blueprint.Import()?)", pkgName)
206*1fa6dee9SAndroid Build Coastguard Worker}
207*1fa6dee9SAndroid Build Coastguard Worker
208*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) AddImport(name string, importedScope *basicScope) error {
209*1fa6dee9SAndroid Build Coastguard Worker	_, present := s.imports[name]
210*1fa6dee9SAndroid Build Coastguard Worker	if present {
211*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf("import %q is already defined in this scope", name)
212*1fa6dee9SAndroid Build Coastguard Worker	}
213*1fa6dee9SAndroid Build Coastguard Worker	s.imports[name] = importedScope
214*1fa6dee9SAndroid Build Coastguard Worker	return nil
215*1fa6dee9SAndroid Build Coastguard Worker}
216*1fa6dee9SAndroid Build Coastguard Worker
217*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) AddVariable(v Variable) error {
218*1fa6dee9SAndroid Build Coastguard Worker	name := v.name()
219*1fa6dee9SAndroid Build Coastguard Worker	_, present := s.variables[name]
220*1fa6dee9SAndroid Build Coastguard Worker	if present {
221*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf("variable %q is already defined in this scope", name)
222*1fa6dee9SAndroid Build Coastguard Worker	}
223*1fa6dee9SAndroid Build Coastguard Worker	s.variables[name] = v
224*1fa6dee9SAndroid Build Coastguard Worker	return nil
225*1fa6dee9SAndroid Build Coastguard Worker}
226*1fa6dee9SAndroid Build Coastguard Worker
227*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) AddPool(p Pool) error {
228*1fa6dee9SAndroid Build Coastguard Worker	name := p.name()
229*1fa6dee9SAndroid Build Coastguard Worker	_, present := s.pools[name]
230*1fa6dee9SAndroid Build Coastguard Worker	if present {
231*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf("pool %q is already defined in this scope", name)
232*1fa6dee9SAndroid Build Coastguard Worker	}
233*1fa6dee9SAndroid Build Coastguard Worker	s.pools[name] = p
234*1fa6dee9SAndroid Build Coastguard Worker	return nil
235*1fa6dee9SAndroid Build Coastguard Worker}
236*1fa6dee9SAndroid Build Coastguard Worker
237*1fa6dee9SAndroid Build Coastguard Workerfunc (s *basicScope) AddRule(r Rule) error {
238*1fa6dee9SAndroid Build Coastguard Worker	name := r.name()
239*1fa6dee9SAndroid Build Coastguard Worker	_, present := s.rules[name]
240*1fa6dee9SAndroid Build Coastguard Worker	if present {
241*1fa6dee9SAndroid Build Coastguard Worker		return fmt.Errorf("rule %q is already defined in this scope", name)
242*1fa6dee9SAndroid Build Coastguard Worker	}
243*1fa6dee9SAndroid Build Coastguard Worker	s.rules[name] = r
244*1fa6dee9SAndroid Build Coastguard Worker	return nil
245*1fa6dee9SAndroid Build Coastguard Worker}
246*1fa6dee9SAndroid Build Coastguard Worker
247*1fa6dee9SAndroid Build Coastguard Workertype localScope struct {
248*1fa6dee9SAndroid Build Coastguard Worker	namePrefix string
249*1fa6dee9SAndroid Build Coastguard Worker	scope      *basicScope
250*1fa6dee9SAndroid Build Coastguard Worker}
251*1fa6dee9SAndroid Build Coastguard Worker
252*1fa6dee9SAndroid Build Coastguard Workerfunc newLocalScope(parent *basicScope, namePrefix string) *localScope {
253*1fa6dee9SAndroid Build Coastguard Worker	return &localScope{
254*1fa6dee9SAndroid Build Coastguard Worker		namePrefix: namePrefix,
255*1fa6dee9SAndroid Build Coastguard Worker		scope:      newScope(parent),
256*1fa6dee9SAndroid Build Coastguard Worker	}
257*1fa6dee9SAndroid Build Coastguard Worker}
258*1fa6dee9SAndroid Build Coastguard Worker
259*1fa6dee9SAndroid Build Coastguard Worker// ReparentTo sets the localScope's parent scope to the scope of the given
260*1fa6dee9SAndroid Build Coastguard Worker// package context.  This allows a ModuleContext and SingletonContext to call
261*1fa6dee9SAndroid Build Coastguard Worker// a function defined in a different Go package and have that function retain
262*1fa6dee9SAndroid Build Coastguard Worker// access to all of the package-scoped variables of its own package.
263*1fa6dee9SAndroid Build Coastguard Workerfunc (s *localScope) ReparentTo(pctx PackageContext) {
264*1fa6dee9SAndroid Build Coastguard Worker	s.scope.parent = pctx.getScope()
265*1fa6dee9SAndroid Build Coastguard Worker}
266*1fa6dee9SAndroid Build Coastguard Worker
267*1fa6dee9SAndroid Build Coastguard Workerfunc (s *localScope) LookupVariable(name string) (Variable, error) {
268*1fa6dee9SAndroid Build Coastguard Worker	return s.scope.LookupVariable(name)
269*1fa6dee9SAndroid Build Coastguard Worker}
270*1fa6dee9SAndroid Build Coastguard Worker
271*1fa6dee9SAndroid Build Coastguard Workerfunc (s *localScope) IsRuleVisible(rule Rule) bool {
272*1fa6dee9SAndroid Build Coastguard Worker	return s.scope.IsRuleVisible(rule)
273*1fa6dee9SAndroid Build Coastguard Worker}
274*1fa6dee9SAndroid Build Coastguard Worker
275*1fa6dee9SAndroid Build Coastguard Workerfunc (s *localScope) IsPoolVisible(pool Pool) bool {
276*1fa6dee9SAndroid Build Coastguard Worker	return s.scope.IsPoolVisible(pool)
277*1fa6dee9SAndroid Build Coastguard Worker}
278*1fa6dee9SAndroid Build Coastguard Worker
279*1fa6dee9SAndroid Build Coastguard Workerfunc (s *localScope) AddLocalVariable(name, value string) (*localVariable,
280*1fa6dee9SAndroid Build Coastguard Worker	error) {
281*1fa6dee9SAndroid Build Coastguard Worker
282*1fa6dee9SAndroid Build Coastguard Worker	err := validateNinjaName(name)
283*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
284*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
285*1fa6dee9SAndroid Build Coastguard Worker	}
286*1fa6dee9SAndroid Build Coastguard Worker
287*1fa6dee9SAndroid Build Coastguard Worker	if strings.ContainsRune(name, '.') {
288*1fa6dee9SAndroid Build Coastguard Worker		return nil, fmt.Errorf("local variable name %q contains '.'", name)
289*1fa6dee9SAndroid Build Coastguard Worker	}
290*1fa6dee9SAndroid Build Coastguard Worker
291*1fa6dee9SAndroid Build Coastguard Worker	ninjaValue, err := parseNinjaString(s.scope, value)
292*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
293*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
294*1fa6dee9SAndroid Build Coastguard Worker	}
295*1fa6dee9SAndroid Build Coastguard Worker
296*1fa6dee9SAndroid Build Coastguard Worker	v := &localVariable{
297*1fa6dee9SAndroid Build Coastguard Worker		fullName_: s.namePrefix + name,
298*1fa6dee9SAndroid Build Coastguard Worker		name_:     name,
299*1fa6dee9SAndroid Build Coastguard Worker		value_:    ninjaValue,
300*1fa6dee9SAndroid Build Coastguard Worker	}
301*1fa6dee9SAndroid Build Coastguard Worker
302*1fa6dee9SAndroid Build Coastguard Worker	err = s.scope.AddVariable(v)
303*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
304*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
305*1fa6dee9SAndroid Build Coastguard Worker	}
306*1fa6dee9SAndroid Build Coastguard Worker
307*1fa6dee9SAndroid Build Coastguard Worker	return v, nil
308*1fa6dee9SAndroid Build Coastguard Worker}
309*1fa6dee9SAndroid Build Coastguard Worker
310*1fa6dee9SAndroid Build Coastguard Workerfunc (s *localScope) AddLocalRule(name string, params *RuleParams,
311*1fa6dee9SAndroid Build Coastguard Worker	argNames ...string) (*localRule, error) {
312*1fa6dee9SAndroid Build Coastguard Worker
313*1fa6dee9SAndroid Build Coastguard Worker	err := validateNinjaName(name)
314*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
315*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
316*1fa6dee9SAndroid Build Coastguard Worker	}
317*1fa6dee9SAndroid Build Coastguard Worker
318*1fa6dee9SAndroid Build Coastguard Worker	err = validateArgNames(argNames)
319*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
320*1fa6dee9SAndroid Build Coastguard Worker		return nil, fmt.Errorf("invalid argument name: %s", err)
321*1fa6dee9SAndroid Build Coastguard Worker	}
322*1fa6dee9SAndroid Build Coastguard Worker
323*1fa6dee9SAndroid Build Coastguard Worker	argNamesSet := make(map[string]bool)
324*1fa6dee9SAndroid Build Coastguard Worker	for _, argName := range argNames {
325*1fa6dee9SAndroid Build Coastguard Worker		argNamesSet[argName] = true
326*1fa6dee9SAndroid Build Coastguard Worker	}
327*1fa6dee9SAndroid Build Coastguard Worker
328*1fa6dee9SAndroid Build Coastguard Worker	ruleScope := makeRuleScope(s.scope, argNamesSet)
329*1fa6dee9SAndroid Build Coastguard Worker
330*1fa6dee9SAndroid Build Coastguard Worker	def, err := parseRuleParams(ruleScope, params)
331*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
332*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
333*1fa6dee9SAndroid Build Coastguard Worker	}
334*1fa6dee9SAndroid Build Coastguard Worker
335*1fa6dee9SAndroid Build Coastguard Worker	r := &localRule{
336*1fa6dee9SAndroid Build Coastguard Worker		fullName_: s.namePrefix + name,
337*1fa6dee9SAndroid Build Coastguard Worker		name_:     name,
338*1fa6dee9SAndroid Build Coastguard Worker		def_:      def,
339*1fa6dee9SAndroid Build Coastguard Worker		argNames:  argNamesSet,
340*1fa6dee9SAndroid Build Coastguard Worker		scope_:    ruleScope,
341*1fa6dee9SAndroid Build Coastguard Worker	}
342*1fa6dee9SAndroid Build Coastguard Worker
343*1fa6dee9SAndroid Build Coastguard Worker	err = s.scope.AddRule(r)
344*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
345*1fa6dee9SAndroid Build Coastguard Worker		return nil, err
346*1fa6dee9SAndroid Build Coastguard Worker	}
347*1fa6dee9SAndroid Build Coastguard Worker
348*1fa6dee9SAndroid Build Coastguard Worker	return r, nil
349*1fa6dee9SAndroid Build Coastguard Worker}
350*1fa6dee9SAndroid Build Coastguard Worker
351*1fa6dee9SAndroid Build Coastguard Workertype localVariable struct {
352*1fa6dee9SAndroid Build Coastguard Worker	fullName_ string
353*1fa6dee9SAndroid Build Coastguard Worker	name_     string
354*1fa6dee9SAndroid Build Coastguard Worker	value_    *ninjaString
355*1fa6dee9SAndroid Build Coastguard Worker}
356*1fa6dee9SAndroid Build Coastguard Worker
357*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localVariable) packageContext() *packageContext {
358*1fa6dee9SAndroid Build Coastguard Worker	return nil
359*1fa6dee9SAndroid Build Coastguard Worker}
360*1fa6dee9SAndroid Build Coastguard Worker
361*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localVariable) name() string {
362*1fa6dee9SAndroid Build Coastguard Worker	return l.name_
363*1fa6dee9SAndroid Build Coastguard Worker}
364*1fa6dee9SAndroid Build Coastguard Worker
365*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localVariable) fullName(pkgNames map[*packageContext]string) string {
366*1fa6dee9SAndroid Build Coastguard Worker	return l.fullName_
367*1fa6dee9SAndroid Build Coastguard Worker}
368*1fa6dee9SAndroid Build Coastguard Worker
369*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localVariable) value(VariableFuncContext, interface{}) (*ninjaString, error) {
370*1fa6dee9SAndroid Build Coastguard Worker	return l.value_, nil
371*1fa6dee9SAndroid Build Coastguard Worker}
372*1fa6dee9SAndroid Build Coastguard Worker
373*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localVariable) String() string {
374*1fa6dee9SAndroid Build Coastguard Worker	return "<local var>:" + l.fullName_
375*1fa6dee9SAndroid Build Coastguard Worker}
376*1fa6dee9SAndroid Build Coastguard Worker
377*1fa6dee9SAndroid Build Coastguard Workertype localRule struct {
378*1fa6dee9SAndroid Build Coastguard Worker	fullName_ string
379*1fa6dee9SAndroid Build Coastguard Worker	name_     string
380*1fa6dee9SAndroid Build Coastguard Worker	def_      *ruleDef
381*1fa6dee9SAndroid Build Coastguard Worker	argNames  map[string]bool
382*1fa6dee9SAndroid Build Coastguard Worker	scope_    *basicScope
383*1fa6dee9SAndroid Build Coastguard Worker}
384*1fa6dee9SAndroid Build Coastguard Worker
385*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localRule) packageContext() *packageContext {
386*1fa6dee9SAndroid Build Coastguard Worker	return nil
387*1fa6dee9SAndroid Build Coastguard Worker}
388*1fa6dee9SAndroid Build Coastguard Worker
389*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localRule) name() string {
390*1fa6dee9SAndroid Build Coastguard Worker	return l.name_
391*1fa6dee9SAndroid Build Coastguard Worker}
392*1fa6dee9SAndroid Build Coastguard Worker
393*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localRule) fullName(pkgNames map[*packageContext]string) string {
394*1fa6dee9SAndroid Build Coastguard Worker	return l.fullName_
395*1fa6dee9SAndroid Build Coastguard Worker}
396*1fa6dee9SAndroid Build Coastguard Worker
397*1fa6dee9SAndroid Build Coastguard Workerfunc (l *localRule) def(interface{}) (*ruleDef, error) {
398*1fa6dee9SAndroid Build Coastguard Worker	return l.def_, nil
399*1fa6dee9SAndroid Build Coastguard Worker}
400*1fa6dee9SAndroid Build Coastguard Worker
401*1fa6dee9SAndroid Build Coastguard Workerfunc (r *localRule) scope() *basicScope {
402*1fa6dee9SAndroid Build Coastguard Worker	return r.scope_
403*1fa6dee9SAndroid Build Coastguard Worker}
404*1fa6dee9SAndroid Build Coastguard Worker
405*1fa6dee9SAndroid Build Coastguard Workerfunc (r *localRule) isArg(argName string) bool {
406*1fa6dee9SAndroid Build Coastguard Worker	return r.argNames[argName]
407*1fa6dee9SAndroid Build Coastguard Worker}
408*1fa6dee9SAndroid Build Coastguard Worker
409*1fa6dee9SAndroid Build Coastguard Workerfunc (r *localRule) String() string {
410*1fa6dee9SAndroid Build Coastguard Worker	return "<local rule>:" + r.fullName_
411*1fa6dee9SAndroid Build Coastguard Worker}
412*1fa6dee9SAndroid Build Coastguard Worker
413*1fa6dee9SAndroid Build Coastguard Workertype nameTracker struct {
414*1fa6dee9SAndroid Build Coastguard Worker	variables map[Variable]string
415*1fa6dee9SAndroid Build Coastguard Worker	rules     map[Rule]string
416*1fa6dee9SAndroid Build Coastguard Worker	pools     map[Pool]string
417*1fa6dee9SAndroid Build Coastguard Worker
418*1fa6dee9SAndroid Build Coastguard Worker	pkgNames map[*packageContext]string
419*1fa6dee9SAndroid Build Coastguard Worker}
420*1fa6dee9SAndroid Build Coastguard Worker
421*1fa6dee9SAndroid Build Coastguard Workerfunc (m *nameTracker) Variable(v Variable) string {
422*1fa6dee9SAndroid Build Coastguard Worker	if m == nil {
423*1fa6dee9SAndroid Build Coastguard Worker		return v.fullName(nil)
424*1fa6dee9SAndroid Build Coastguard Worker	}
425*1fa6dee9SAndroid Build Coastguard Worker	if name, ok := m.variables[v]; ok {
426*1fa6dee9SAndroid Build Coastguard Worker		return name
427*1fa6dee9SAndroid Build Coastguard Worker	}
428*1fa6dee9SAndroid Build Coastguard Worker	return v.fullName(m.pkgNames)
429*1fa6dee9SAndroid Build Coastguard Worker}
430*1fa6dee9SAndroid Build Coastguard Worker
431*1fa6dee9SAndroid Build Coastguard Workerfunc (m *nameTracker) Rule(r Rule) string {
432*1fa6dee9SAndroid Build Coastguard Worker	if m == nil {
433*1fa6dee9SAndroid Build Coastguard Worker		return r.fullName(nil)
434*1fa6dee9SAndroid Build Coastguard Worker	}
435*1fa6dee9SAndroid Build Coastguard Worker	if name, ok := m.rules[r]; ok {
436*1fa6dee9SAndroid Build Coastguard Worker		return name
437*1fa6dee9SAndroid Build Coastguard Worker	}
438*1fa6dee9SAndroid Build Coastguard Worker	return r.fullName(m.pkgNames)
439*1fa6dee9SAndroid Build Coastguard Worker}
440*1fa6dee9SAndroid Build Coastguard Worker
441*1fa6dee9SAndroid Build Coastguard Workerfunc (m *nameTracker) Pool(p Pool) string {
442*1fa6dee9SAndroid Build Coastguard Worker	if m == nil {
443*1fa6dee9SAndroid Build Coastguard Worker		return p.fullName(nil)
444*1fa6dee9SAndroid Build Coastguard Worker	}
445*1fa6dee9SAndroid Build Coastguard Worker	if name, ok := m.pools[p]; ok {
446*1fa6dee9SAndroid Build Coastguard Worker		return name
447*1fa6dee9SAndroid Build Coastguard Worker	}
448*1fa6dee9SAndroid Build Coastguard Worker	return p.fullName(m.pkgNames)
449*1fa6dee9SAndroid Build Coastguard Worker}
450