github.com/colincross/blueprint@v0.0.0-20150626231830-9c067caf2eb5/package_ctx.go (about) 1 // Copyright 2014 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 15 package blueprint 16 17 import ( 18 "errors" 19 "fmt" 20 "reflect" 21 "runtime" 22 "strings" 23 "sync" 24 ) 25 26 // A PackageContext provides a way to create package-scoped Ninja pools, 27 // rules, and variables. A Go package should create a single unexported 28 // package-scoped PackageContext variable that it uses to create all package- 29 // scoped Ninja object definitions. This PackageContext object should then be 30 // passed to all calls to define module- or singleton-specific Ninja 31 // definitions. For example: 32 // 33 // package blah 34 // 35 // import ( 36 // "blueprint" 37 // ) 38 // 39 // var ( 40 // pctx = NewPackageContext("path/to/blah") 41 // 42 // myPrivateVar = pctx.StaticVariable("myPrivateVar", "abcdef") 43 // MyExportedVar = pctx.StaticVariable("MyExportedVar", "$myPrivateVar 123456!") 44 // 45 // SomeRule = pctx.StaticRule(...) 46 // ) 47 // 48 // // ... 49 // 50 // func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) { 51 // ctx.Build(pctx, blueprint.BuildParams{ 52 // Rule: SomeRule, 53 // Outputs: []string{"$myPrivateVar"}, 54 // }) 55 // } 56 type PackageContext struct { 57 fullName string 58 shortName string 59 pkgPath string 60 scope *basicScope 61 } 62 63 var packageContexts = map[string]*PackageContext{} 64 65 // NewPackageContext creates a PackageContext object for a given package. The 66 // pkgPath argument should always be set to the full path used to import the 67 // package. This function may only be called from a Go package's init() 68 // function or as part of a package-scoped variable initialization. 69 func NewPackageContext(pkgPath string) *PackageContext { 70 checkCalledFromInit() 71 72 if _, present := packageContexts[pkgPath]; present { 73 panic(fmt.Errorf("package %q already has a package context")) 74 } 75 76 pkgName := pkgPathToName(pkgPath) 77 err := validateNinjaName(pkgName) 78 if err != nil { 79 panic(err) 80 } 81 82 i := strings.LastIndex(pkgPath, "/") 83 shortName := pkgPath[i+1:] 84 85 p := &PackageContext{ 86 fullName: pkgName, 87 shortName: shortName, 88 pkgPath: pkgPath, 89 scope: newScope(nil), 90 } 91 92 packageContexts[pkgPath] = p 93 94 return p 95 } 96 97 var Phony Rule = &builtinRule{ 98 name_: "phony", 99 } 100 101 var Console Pool = &builtinPool{ 102 name_: "console", 103 } 104 105 var errRuleIsBuiltin = errors.New("the rule is a built-in") 106 var errPoolIsBuiltin = errors.New("the pool is a built-in") 107 var errVariableIsArg = errors.New("argument variables have no value") 108 109 // checkCalledFromInit panics if a Go package's init function is not on the 110 // call stack. 111 func checkCalledFromInit() { 112 for skip := 3; ; skip++ { 113 _, funcName, ok := callerName(skip) 114 if !ok { 115 panic("not called from an init func") 116 } 117 118 if funcName == "init" || strings.HasPrefix(funcName, "init·") { 119 return 120 } 121 } 122 } 123 124 // callerName returns the package path and function name of the calling 125 // function. The skip argument has the same meaning as the skip argument of 126 // runtime.Callers. 127 func callerName(skip int) (pkgPath, funcName string, ok bool) { 128 var pc [1]uintptr 129 n := runtime.Callers(skip+1, pc[:]) 130 if n != 1 { 131 return "", "", false 132 } 133 134 f := runtime.FuncForPC(pc[0]) 135 fullName := f.Name() 136 137 lastDotIndex := strings.LastIndex(fullName, ".") 138 if lastDotIndex == -1 { 139 panic("unable to distinguish function name from package") 140 } 141 142 if fullName[lastDotIndex-1] == ')' { 143 // The caller is a method on some type, so it's name looks like 144 // "pkg/path.(type).method". We need to go back one dot farther to get 145 // to the package name. 146 lastDotIndex = strings.LastIndex(fullName[:lastDotIndex], ".") 147 } 148 149 pkgPath = fullName[:lastDotIndex] 150 funcName = fullName[lastDotIndex+1:] 151 ok = true 152 return 153 } 154 155 // pkgPathToName makes a Ninja-friendly name out of a Go package name by 156 // replaceing all the '/' characters with '.'. We assume the results are 157 // unique, though this is not 100% guaranteed for Go package names that 158 // already contain '.' characters. Disallowing package names with '.' isn't 159 // reasonable since many package names contain the name of the hosting site 160 // (e.g. "code.google.com"). In practice this probably isn't really a 161 // problem. 162 func pkgPathToName(pkgPath string) string { 163 return strings.Replace(pkgPath, "/", ".", -1) 164 } 165 166 // Import enables access to the exported Ninja pools, rules, and variables 167 // that are defined at the package scope of another Go package. Go's 168 // visibility rules apply to these references - capitalized names indicate 169 // that something is exported. It may only be called from a Go package's 170 // init() function. The Go package path passed to Import must have already 171 // been imported into the Go package using a Go import statement. The 172 // imported variables may then be accessed from Ninja strings as 173 // "${pkg.Variable}", while the imported rules can simply be accessed as 174 // exported Go variables from the package. For example: 175 // 176 // import ( 177 // "blueprint" 178 // "foo/bar" 179 // ) 180 // 181 // var pctx = NewPackagePath("blah") 182 // 183 // func init() { 184 // pctx.Import("foo/bar") 185 // } 186 // 187 // ... 188 // 189 // func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) { 190 // ctx.Build(pctx, blueprint.BuildParams{ 191 // Rule: bar.SomeRule, 192 // Outputs: []string{"${bar.SomeVariable}"}, 193 // }) 194 // } 195 // 196 // Note that the local name used to refer to the package in Ninja variable names 197 // is derived from pkgPath by extracting the last path component. This differs 198 // from Go's import declaration, which derives the local name from the package 199 // clause in the imported package. By convention these names are made to match, 200 // but this is not required. 201 func (p *PackageContext) Import(pkgPath string) { 202 checkCalledFromInit() 203 importPkg, ok := packageContexts[pkgPath] 204 if !ok { 205 panic(fmt.Errorf("package %q has no context", pkgPath)) 206 } 207 208 err := p.scope.AddImport(importPkg.shortName, importPkg.scope) 209 if err != nil { 210 panic(err) 211 } 212 } 213 214 // ImportAs provides the same functionality as Import, but it allows the local 215 // name that will be used to refer to the package to be specified explicitly. 216 // It may only be called from a Go package's init() function. 217 func (p *PackageContext) ImportAs(as, pkgPath string) { 218 checkCalledFromInit() 219 importPkg, ok := packageContexts[pkgPath] 220 if !ok { 221 panic(fmt.Errorf("package %q has no context", pkgPath)) 222 } 223 224 err := validateNinjaName(as) 225 if err != nil { 226 panic(err) 227 } 228 229 err = p.scope.AddImport(as, importPkg.scope) 230 if err != nil { 231 panic(err) 232 } 233 } 234 235 type staticVariable struct { 236 pctx *PackageContext 237 name_ string 238 value_ string 239 } 240 241 // StaticVariable returns a Variable whose value does not depend on any 242 // configuration information. It may only be called during a Go package's 243 // initialization - either from the init() function or as part of a package- 244 // scoped variable's initialization. 245 // 246 // This function is usually used to initialize a package-scoped Go variable that 247 // represents a Ninja variable that will be output. The name argument should 248 // exactly match the Go variable name, and the value string may reference other 249 // Ninja variables that are visible within the calling Go package. 250 func (p *PackageContext) StaticVariable(name, value string) Variable { 251 checkCalledFromInit() 252 err := validateNinjaName(name) 253 if err != nil { 254 panic(err) 255 } 256 257 v := &staticVariable{p, name, value} 258 err = p.scope.AddVariable(v) 259 if err != nil { 260 panic(err) 261 } 262 263 return v 264 } 265 266 func (v *staticVariable) packageContext() *PackageContext { 267 return v.pctx 268 } 269 270 func (v *staticVariable) name() string { 271 return v.name_ 272 } 273 274 func (v *staticVariable) fullName(pkgNames map[*PackageContext]string) string { 275 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ 276 } 277 278 func (v *staticVariable) value(interface{}) (*ninjaString, error) { 279 ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_) 280 if err != nil { 281 err = fmt.Errorf("error parsing variable %s value: %s", v, err) 282 panic(err) 283 } 284 return ninjaStr, nil 285 } 286 287 func (v *staticVariable) String() string { 288 return v.pctx.pkgPath + "." + v.name_ 289 } 290 291 type variableFunc struct { 292 pctx *PackageContext 293 name_ string 294 value_ func(interface{}) (string, error) 295 } 296 297 // VariableFunc returns a Variable whose value is determined by a function that 298 // takes a config object as input and returns either the variable value or an 299 // error. It may only be called during a Go package's initialization - either 300 // from the init() function or as part of a package-scoped variable's 301 // initialization. 302 // 303 // This function is usually used to initialize a package-scoped Go variable that 304 // represents a Ninja variable that will be output. The name argument should 305 // exactly match the Go variable name, and the value string returned by f may 306 // reference other Ninja variables that are visible within the calling Go 307 // package. 308 func (p *PackageContext) VariableFunc(name string, 309 f func(config interface{}) (string, error)) Variable { 310 311 checkCalledFromInit() 312 313 err := validateNinjaName(name) 314 if err != nil { 315 panic(err) 316 } 317 318 v := &variableFunc{p, name, f} 319 err = p.scope.AddVariable(v) 320 if err != nil { 321 panic(err) 322 } 323 324 return v 325 } 326 327 // VariableConfigMethod returns a Variable whose value is determined by calling 328 // a method on the config object. The method must take no arguments and return 329 // a single string that will be the variable's value. It may only be called 330 // during a Go package's initialization - either from the init() function or as 331 // part of a package-scoped variable's initialization. 332 // 333 // This function is usually used to initialize a package-scoped Go variable that 334 // represents a Ninja variable that will be output. The name argument should 335 // exactly match the Go variable name, and the value string returned by method 336 // may reference other Ninja variables that are visible within the calling Go 337 // package. 338 func (p *PackageContext) VariableConfigMethod(name string, 339 method interface{}) Variable { 340 341 checkCalledFromInit() 342 343 err := validateNinjaName(name) 344 if err != nil { 345 panic(err) 346 } 347 348 methodValue := reflect.ValueOf(method) 349 validateVariableMethod(name, methodValue) 350 351 fun := func(config interface{}) (string, error) { 352 result := methodValue.Call([]reflect.Value{reflect.ValueOf(config)}) 353 resultStr := result[0].Interface().(string) 354 return resultStr, nil 355 } 356 357 v := &variableFunc{p, name, fun} 358 err = p.scope.AddVariable(v) 359 if err != nil { 360 panic(err) 361 } 362 363 return v 364 } 365 366 func (v *variableFunc) packageContext() *PackageContext { 367 return v.pctx 368 } 369 370 func (v *variableFunc) name() string { 371 return v.name_ 372 } 373 374 func (v *variableFunc) fullName(pkgNames map[*PackageContext]string) string { 375 return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ 376 } 377 378 func (v *variableFunc) value(config interface{}) (*ninjaString, error) { 379 value, err := v.value_(config) 380 if err != nil { 381 return nil, err 382 } 383 384 ninjaStr, err := parseNinjaString(v.pctx.scope, value) 385 if err != nil { 386 err = fmt.Errorf("error parsing variable %s value: %s", v, err) 387 panic(err) 388 } 389 390 return ninjaStr, nil 391 } 392 393 func (v *variableFunc) String() string { 394 return v.pctx.pkgPath + "." + v.name_ 395 } 396 397 func validateVariableMethod(name string, methodValue reflect.Value) { 398 methodType := methodValue.Type() 399 if methodType.Kind() != reflect.Func { 400 panic(fmt.Errorf("method given for variable %s is not a function", 401 name)) 402 } 403 if n := methodType.NumIn(); n != 1 { 404 panic(fmt.Errorf("method for variable %s has %d inputs (should be 1)", 405 name, n)) 406 } 407 if n := methodType.NumOut(); n != 1 { 408 panic(fmt.Errorf("method for variable %s has %d outputs (should be 1)", 409 name, n)) 410 } 411 if kind := methodType.Out(0).Kind(); kind != reflect.String { 412 panic(fmt.Errorf("method for variable %s does not return a string", 413 name)) 414 } 415 } 416 417 // An argVariable is a Variable that exists only when it is set by a build 418 // statement to pass a value to the rule being invoked. It has no value, so it 419 // can never be used to create a Ninja assignment statement. It is inserted 420 // into the rule's scope, which is used for name lookups within the rule and 421 // when assigning argument values as part of a build statement. 422 type argVariable struct { 423 name_ string 424 } 425 426 func (v *argVariable) packageContext() *PackageContext { 427 panic("this should not be called") 428 } 429 430 func (v *argVariable) name() string { 431 return v.name_ 432 } 433 434 func (v *argVariable) fullName(pkgNames map[*PackageContext]string) string { 435 return v.name_ 436 } 437 438 func (v *argVariable) value(config interface{}) (*ninjaString, error) { 439 return nil, errVariableIsArg 440 } 441 442 func (v *argVariable) String() string { 443 return "<arg>:" + v.name_ 444 } 445 446 type staticPool struct { 447 pctx *PackageContext 448 name_ string 449 params PoolParams 450 } 451 452 // StaticPool returns a Pool whose value does not depend on any configuration 453 // information. It may only be called during a Go package's initialization - 454 // either from the init() function or as part of a package-scoped Go variable's 455 // initialization. 456 // 457 // This function is usually used to initialize a package-scoped Go variable that 458 // represents a Ninja pool that will be output. The name argument should 459 // exactly match the Go variable name, and the params fields may reference other 460 // Ninja variables that are visible within the calling Go package. 461 func (p *PackageContext) StaticPool(name string, params PoolParams) Pool { 462 checkCalledFromInit() 463 464 err := validateNinjaName(name) 465 if err != nil { 466 panic(err) 467 } 468 469 pool := &staticPool{p, name, params} 470 err = p.scope.AddPool(pool) 471 if err != nil { 472 panic(err) 473 } 474 475 return pool 476 } 477 478 func (p *staticPool) packageContext() *PackageContext { 479 return p.pctx 480 } 481 482 func (p *staticPool) name() string { 483 return p.name_ 484 } 485 486 func (p *staticPool) fullName(pkgNames map[*PackageContext]string) string { 487 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ 488 } 489 490 func (p *staticPool) def(config interface{}) (*poolDef, error) { 491 def, err := parsePoolParams(p.pctx.scope, &p.params) 492 if err != nil { 493 panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err)) 494 } 495 return def, nil 496 } 497 498 func (p *staticPool) String() string { 499 return p.pctx.pkgPath + "." + p.name_ 500 } 501 502 type poolFunc struct { 503 pctx *PackageContext 504 name_ string 505 paramsFunc func(interface{}) (PoolParams, error) 506 } 507 508 // PoolFunc returns a Pool whose value is determined by a function that takes a 509 // config object as input and returns either the pool parameters or an error. It 510 // may only be called during a Go package's initialization - either from the 511 // init() function or as part of a package-scoped variable's initialization. 512 // 513 // This function is usually used to initialize a package-scoped Go variable that 514 // represents a Ninja pool that will be output. The name argument should 515 // exactly match the Go variable name, and the string fields of the PoolParams 516 // returned by f may reference other Ninja variables that are visible within the 517 // calling Go package. 518 func (p *PackageContext) PoolFunc(name string, f func(interface{}) (PoolParams, 519 error)) Pool { 520 521 checkCalledFromInit() 522 523 err := validateNinjaName(name) 524 if err != nil { 525 panic(err) 526 } 527 528 pool := &poolFunc{p, name, f} 529 err = p.scope.AddPool(pool) 530 if err != nil { 531 panic(err) 532 } 533 534 return pool 535 } 536 537 func (p *poolFunc) packageContext() *PackageContext { 538 return p.pctx 539 } 540 541 func (p *poolFunc) name() string { 542 return p.name_ 543 } 544 545 func (p *poolFunc) fullName(pkgNames map[*PackageContext]string) string { 546 return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ 547 } 548 549 func (p *poolFunc) def(config interface{}) (*poolDef, error) { 550 params, err := p.paramsFunc(config) 551 if err != nil { 552 return nil, err 553 } 554 def, err := parsePoolParams(p.pctx.scope, ¶ms) 555 if err != nil { 556 panic(fmt.Errorf("error parsing PoolParams for %s: %s", p, err)) 557 } 558 return def, nil 559 } 560 561 func (p *poolFunc) String() string { 562 return p.pctx.pkgPath + "." + p.name_ 563 } 564 565 type builtinPool struct { 566 name_ string 567 } 568 569 func (p *builtinPool) packageContext() *PackageContext { 570 return nil 571 } 572 573 func (p *builtinPool) name() string { 574 return p.name_ 575 } 576 577 func (p *builtinPool) fullName(pkgNames map[*PackageContext]string) string { 578 return p.name_ 579 } 580 581 func (p *builtinPool) def(config interface{}) (*poolDef, error) { 582 return nil, errPoolIsBuiltin 583 } 584 585 func (p *builtinPool) String() string { 586 return "<builtin>:" + p.name_ 587 } 588 589 type staticRule struct { 590 pctx *PackageContext 591 name_ string 592 params RuleParams 593 argNames map[string]bool 594 scope_ *basicScope 595 sync.Mutex // protects scope_ during lazy creation 596 } 597 598 // StaticRule returns a Rule whose value does not depend on any configuration 599 // information. It may only be called during a Go package's initialization - 600 // either from the init() function or as part of a package-scoped Go variable's 601 // initialization. 602 // 603 // This function is usually used to initialize a package-scoped Go variable that 604 // represents a Ninja rule that will be output. The name argument should 605 // exactly match the Go variable name, and the params fields may reference other 606 // Ninja variables that are visible within the calling Go package. 607 // 608 // The argNames arguments list Ninja variables that may be overridden by Ninja 609 // build statements that invoke the rule. These arguments may be referenced in 610 // any of the string fields of params. Arguments can shadow package-scoped 611 // variables defined within the caller's Go package, but they may not shadow 612 // those defined in another package. Shadowing a package-scoped variable 613 // results in the package-scoped variable's value being used for build 614 // statements that do not override the argument. For argument names that do not 615 // shadow package-scoped variables the default value is an empty string. 616 func (p *PackageContext) StaticRule(name string, params RuleParams, 617 argNames ...string) Rule { 618 619 checkCalledFromInit() 620 621 err := validateNinjaName(name) 622 if err != nil { 623 panic(err) 624 } 625 626 err = validateArgNames(argNames) 627 if err != nil { 628 panic(fmt.Errorf("invalid argument name: %s", err)) 629 } 630 631 argNamesSet := make(map[string]bool) 632 for _, argName := range argNames { 633 argNamesSet[argName] = true 634 } 635 636 ruleScope := (*basicScope)(nil) // This will get created lazily 637 638 r := &staticRule{ 639 pctx: p, 640 name_: name, 641 params: params, 642 argNames: argNamesSet, 643 scope_: ruleScope, 644 } 645 err = p.scope.AddRule(r) 646 if err != nil { 647 panic(err) 648 } 649 650 return r 651 } 652 653 func (r *staticRule) packageContext() *PackageContext { 654 return r.pctx 655 } 656 657 func (r *staticRule) name() string { 658 return r.name_ 659 } 660 661 func (r *staticRule) fullName(pkgNames map[*PackageContext]string) string { 662 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ 663 } 664 665 func (r *staticRule) def(interface{}) (*ruleDef, error) { 666 def, err := parseRuleParams(r.scope(), &r.params) 667 if err != nil { 668 panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err)) 669 } 670 return def, nil 671 } 672 673 func (r *staticRule) scope() *basicScope { 674 // We lazily create the scope so that all the package-scoped variables get 675 // declared before the args are created. Otherwise we could incorrectly 676 // shadow a package-scoped variable with an arg variable. 677 r.Lock() 678 defer r.Unlock() 679 680 if r.scope_ == nil { 681 r.scope_ = makeRuleScope(r.pctx.scope, r.argNames) 682 } 683 return r.scope_ 684 } 685 686 func (r *staticRule) isArg(argName string) bool { 687 return r.argNames[argName] 688 } 689 690 func (r *staticRule) String() string { 691 return r.pctx.pkgPath + "." + r.name_ 692 } 693 694 type ruleFunc struct { 695 pctx *PackageContext 696 name_ string 697 paramsFunc func(interface{}) (RuleParams, error) 698 argNames map[string]bool 699 scope_ *basicScope 700 sync.Mutex // protects scope_ during lazy creation 701 } 702 703 // RuleFunc returns a Rule whose value is determined by a function that takes a 704 // config object as input and returns either the rule parameters or an error. It 705 // may only be called during a Go package's initialization - either from the 706 // init() function or as part of a package-scoped variable's initialization. 707 // 708 // This function is usually used to initialize a package-scoped Go variable that 709 // represents a Ninja rule that will be output. The name argument should 710 // exactly match the Go variable name, and the string fields of the RuleParams 711 // returned by f may reference other Ninja variables that are visible within the 712 // calling Go package. 713 // 714 // The argNames arguments list Ninja variables that may be overridden by Ninja 715 // build statements that invoke the rule. These arguments may be referenced in 716 // any of the string fields of the RuleParams returned by f. Arguments can 717 // shadow package-scoped variables defined within the caller's Go package, but 718 // they may not shadow those defined in another package. Shadowing a package- 719 // scoped variable results in the package-scoped variable's value being used for 720 // build statements that do not override the argument. For argument names that 721 // do not shadow package-scoped variables the default value is an empty string. 722 func (p *PackageContext) RuleFunc(name string, f func(interface{}) (RuleParams, 723 error), argNames ...string) Rule { 724 725 checkCalledFromInit() 726 727 err := validateNinjaName(name) 728 if err != nil { 729 panic(err) 730 } 731 732 err = validateArgNames(argNames) 733 if err != nil { 734 panic(fmt.Errorf("invalid argument name: %s", err)) 735 } 736 737 argNamesSet := make(map[string]bool) 738 for _, argName := range argNames { 739 argNamesSet[argName] = true 740 } 741 742 ruleScope := (*basicScope)(nil) // This will get created lazily 743 744 rule := &ruleFunc{ 745 pctx: p, 746 name_: name, 747 paramsFunc: f, 748 argNames: argNamesSet, 749 scope_: ruleScope, 750 } 751 err = p.scope.AddRule(rule) 752 if err != nil { 753 panic(err) 754 } 755 756 return rule 757 } 758 759 func (r *ruleFunc) packageContext() *PackageContext { 760 return r.pctx 761 } 762 763 func (r *ruleFunc) name() string { 764 return r.name_ 765 } 766 767 func (r *ruleFunc) fullName(pkgNames map[*PackageContext]string) string { 768 return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ 769 } 770 771 func (r *ruleFunc) def(config interface{}) (*ruleDef, error) { 772 params, err := r.paramsFunc(config) 773 if err != nil { 774 return nil, err 775 } 776 def, err := parseRuleParams(r.scope(), ¶ms) 777 if err != nil { 778 panic(fmt.Errorf("error parsing RuleParams for %s: %s", r, err)) 779 } 780 return def, nil 781 } 782 783 func (r *ruleFunc) scope() *basicScope { 784 // We lazily create the scope so that all the global variables get declared 785 // before the args are created. Otherwise we could incorrectly shadow a 786 // global variable with an arg variable. 787 r.Lock() 788 defer r.Unlock() 789 790 if r.scope_ == nil { 791 r.scope_ = makeRuleScope(r.pctx.scope, r.argNames) 792 } 793 return r.scope_ 794 } 795 796 func (r *ruleFunc) isArg(argName string) bool { 797 return r.argNames[argName] 798 } 799 800 func (r *ruleFunc) String() string { 801 return r.pctx.pkgPath + "." + r.name_ 802 } 803 804 type builtinRule struct { 805 name_ string 806 scope_ *basicScope 807 sync.Mutex // protects scope_ during lazy creation 808 } 809 810 func (r *builtinRule) packageContext() *PackageContext { 811 return nil 812 } 813 814 func (r *builtinRule) name() string { 815 return r.name_ 816 } 817 818 func (r *builtinRule) fullName(pkgNames map[*PackageContext]string) string { 819 return r.name_ 820 } 821 822 func (r *builtinRule) def(config interface{}) (*ruleDef, error) { 823 return nil, errRuleIsBuiltin 824 } 825 826 func (r *builtinRule) scope() *basicScope { 827 r.Lock() 828 defer r.Unlock() 829 830 if r.scope_ == nil { 831 r.scope_ = makeRuleScope(nil, nil) 832 } 833 return r.scope_ 834 } 835 836 func (r *builtinRule) isArg(argName string) bool { 837 return false 838 } 839 840 func (r *builtinRule) String() string { 841 return "<builtin>:" + r.name_ 842 }