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