2014-05-28 01:34:41 +02:00
|
|
|
package blueprint
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
2014-06-06 04:50:44 +02:00
|
|
|
"reflect"
|
2014-05-28 01:34:41 +02:00
|
|
|
"regexp"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type pkg struct {
|
|
|
|
fullName string
|
|
|
|
shortName string
|
|
|
|
pkgPath string
|
|
|
|
scope *scope
|
|
|
|
}
|
|
|
|
|
|
|
|
var pkgs = map[string]*pkg{}
|
|
|
|
|
|
|
|
var pkgRegexp = regexp.MustCompile(`(.*)\.init(·[0-9]+)?`)
|
|
|
|
|
|
|
|
var Phony Rule = &builtinRule{
|
|
|
|
name_: "phony",
|
|
|
|
}
|
|
|
|
|
|
|
|
var errRuleIsBuiltin = errors.New("the rule is a built-in")
|
2014-06-06 04:50:44 +02:00
|
|
|
var errVariableIsArg = errors.New("argument variables have no value")
|
2014-05-28 01:34:41 +02:00
|
|
|
|
|
|
|
// We make a Ninja-friendly name out of a Go package name by replaceing all the
|
|
|
|
// '/' characters with '.'. We assume the results are unique, though this is
|
|
|
|
// not 100% guaranteed for Go package names that already contain '.' characters.
|
|
|
|
// Disallowing package names with '.' isn't reasonable since many package names
|
|
|
|
// contain the name of the hosting site (e.g. "code.google.com"). In practice
|
|
|
|
// this probably isn't really a problem.
|
|
|
|
func pkgPathToName(pkgPath string) string {
|
|
|
|
return strings.Replace(pkgPath, "/", ".", -1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// callerPackage returns the pkg of the function that called the caller of
|
|
|
|
// callerPackage. The caller of callerPackage must have been called from an
|
|
|
|
// init function of the package or callerPackage will panic.
|
|
|
|
//
|
|
|
|
// Looking for the package's init function on the call stack and using that to
|
|
|
|
// determine its package name is unfortunately dependent upon Go runtime
|
|
|
|
// implementation details. However, it allows us to ensure that it's easy to
|
|
|
|
// determine where a definition in a .ninja file came from.
|
|
|
|
func callerPackage() *pkg {
|
|
|
|
var pc [1]uintptr
|
|
|
|
n := runtime.Callers(3, pc[:])
|
|
|
|
if n != 1 {
|
|
|
|
panic("unable to get caller pc")
|
|
|
|
}
|
|
|
|
|
|
|
|
f := runtime.FuncForPC(pc[0])
|
|
|
|
callerName := f.Name()
|
|
|
|
|
|
|
|
submatches := pkgRegexp.FindSubmatch([]byte(callerName))
|
|
|
|
if submatches == nil {
|
|
|
|
println(callerName)
|
|
|
|
panic("not called from an init func")
|
|
|
|
}
|
|
|
|
|
|
|
|
pkgPath := string(submatches[1])
|
|
|
|
|
|
|
|
pkgName := pkgPathToName(pkgPath)
|
|
|
|
err := validateNinjaName(pkgName)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
i := strings.LastIndex(pkgPath, "/")
|
|
|
|
shortName := pkgPath[i+1:]
|
|
|
|
|
|
|
|
p, ok := pkgs[pkgPath]
|
|
|
|
if !ok {
|
|
|
|
p = &pkg{
|
|
|
|
fullName: pkgName,
|
|
|
|
shortName: shortName,
|
|
|
|
pkgPath: pkgPath,
|
|
|
|
scope: newScope(nil),
|
|
|
|
}
|
|
|
|
pkgs[pkgPath] = p
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
2014-06-06 04:50:44 +02:00
|
|
|
// Import enables access to the global Ninja rules and variables that are
|
|
|
|
// exported by another Go package. It may only be called from a Go package's
|
|
|
|
// init() function. The Go package path passed to Import must have already been
|
|
|
|
// imported into the Go package using a Go import statement. The imported
|
|
|
|
// variables may then be accessed from Ninja strings as "${pkg.Variable}", while
|
|
|
|
// the imported rules can simply be accessed as exported Go variables from the
|
|
|
|
// package. For example:
|
|
|
|
//
|
|
|
|
// import (
|
|
|
|
// "blueprint"
|
|
|
|
// "foo/bar"
|
|
|
|
// )
|
|
|
|
//
|
|
|
|
// func init() {
|
|
|
|
// blueprint.Import("foo/bar")
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
// func (m *MyModule) GenerateBuildActions(ctx blueprint.Module) {
|
|
|
|
// ctx.Build(blueprint.BuildParams{
|
|
|
|
// Rule: bar.SomeRule,
|
|
|
|
// Outputs: []string{"${bar.SomeVariable}"},
|
|
|
|
// })
|
|
|
|
// }
|
2014-05-28 01:34:41 +02:00
|
|
|
func Import(pkgPath string) {
|
|
|
|
callerPkg := callerPackage()
|
|
|
|
|
|
|
|
importPkg, ok := pkgs[pkgPath]
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Errorf("package %q has no Blueprints definitions", pkgPath))
|
|
|
|
}
|
|
|
|
|
|
|
|
err := callerPkg.scope.AddImport(importPkg.shortName, importPkg.scope)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ImportAs(as, pkgPath string) {
|
|
|
|
callerPkg := callerPackage()
|
|
|
|
|
|
|
|
importPkg, ok := pkgs[pkgPath]
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Errorf("package %q has no Blueprints definitions", pkgPath))
|
|
|
|
}
|
|
|
|
|
|
|
|
err := validateNinjaName(as)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = callerPkg.scope.AddImport(as, importPkg.scope)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type staticVariable struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
value_ string
|
|
|
|
}
|
|
|
|
|
|
|
|
// StaticVariable returns a Variable that does not depend on any configuration
|
|
|
|
// information.
|
|
|
|
func StaticVariable(name, value string) Variable {
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
v := &staticVariable{pkg, name, value}
|
|
|
|
err = pkg.scope.AddVariable(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *staticVariable) pkg() *pkg {
|
|
|
|
return v.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *staticVariable) name() string {
|
|
|
|
return v.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *staticVariable) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return packageNamespacePrefix(pkgNames[v.pkg_]) + v.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *staticVariable) value(Config) (*ninjaString, error) {
|
|
|
|
return parseNinjaString(v.pkg_.scope, v.value_)
|
|
|
|
}
|
|
|
|
|
|
|
|
type variableFunc struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
value_ func(Config) (string, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// VariableFunc returns a Variable whose value is determined by a function that
|
|
|
|
// takes a Config object as input and returns either the variable value or an
|
|
|
|
// error.
|
|
|
|
func VariableFunc(name string, f func(Config) (string, error)) Variable {
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
v := &variableFunc{pkg, name, f}
|
|
|
|
err = pkg.scope.AddVariable(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2014-06-06 04:50:44 +02:00
|
|
|
// VariableConfigMethod returns a Variable whose value is determined by calling
|
|
|
|
// a method on the Config object. The method must take no arguments and return
|
|
|
|
// a single string that will be the variable's value.
|
|
|
|
func VariableConfigMethod(name string, method interface{}) Variable {
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
methodValue := reflect.ValueOf(method)
|
|
|
|
validateVariableMethod(name, methodValue)
|
|
|
|
|
|
|
|
fun := func(config Config) (string, error) {
|
|
|
|
result := methodValue.Call([]reflect.Value{reflect.ValueOf(config)})
|
|
|
|
resultStr := result[0].Interface().(string)
|
|
|
|
return resultStr, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
v := &variableFunc{pkg, name, fun}
|
|
|
|
err = pkg.scope.AddVariable(v)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
func (v *variableFunc) pkg() *pkg {
|
|
|
|
return v.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *variableFunc) name() string {
|
|
|
|
return v.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *variableFunc) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return packageNamespacePrefix(pkgNames[v.pkg_]) + v.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *variableFunc) value(config Config) (*ninjaString, error) {
|
|
|
|
value, err := v.value_(config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return parseNinjaString(v.pkg_.scope, value)
|
|
|
|
}
|
|
|
|
|
2014-06-06 04:50:44 +02:00
|
|
|
func validateVariableMethod(name string, methodValue reflect.Value) {
|
|
|
|
methodType := methodValue.Type()
|
|
|
|
if methodType.Kind() != reflect.Func {
|
|
|
|
panic(fmt.Errorf("method given for variable %s is not a function",
|
|
|
|
name))
|
|
|
|
}
|
|
|
|
if n := methodType.NumIn(); n != 1 {
|
|
|
|
panic(fmt.Errorf("method for variable %s has %d inputs (should be 1)",
|
|
|
|
name, n))
|
|
|
|
}
|
|
|
|
if n := methodType.NumOut(); n != 1 {
|
|
|
|
panic(fmt.Errorf("method for variable %s has %d outputs (should be 1)",
|
|
|
|
name, n))
|
|
|
|
}
|
|
|
|
if kind := methodType.Out(0).Kind(); kind != reflect.String {
|
|
|
|
panic(fmt.Errorf("method for variable %s does not return a string",
|
|
|
|
name))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-28 01:34:41 +02:00
|
|
|
// An argVariable is a Variable that exists only when it is set by a build
|
|
|
|
// statement to pass a value to the rule being invoked. It has no value, so it
|
|
|
|
// can never be used to create a Ninja assignment statement. It is inserted
|
|
|
|
// into the rule's scope, which is used for name lookups within the rule and
|
|
|
|
// when assigning argument values as part of a build statement.
|
|
|
|
type argVariable struct {
|
|
|
|
name_ string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *argVariable) pkg() *pkg {
|
|
|
|
panic("this should not be called")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *argVariable) name() string {
|
|
|
|
return v.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *argVariable) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return v.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *argVariable) value(config Config) (*ninjaString, error) {
|
|
|
|
return nil, errVariableIsArg
|
|
|
|
}
|
|
|
|
|
|
|
|
type staticPool struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
params PoolParams
|
|
|
|
}
|
|
|
|
|
|
|
|
func StaticPool(name string, params PoolParams) Pool {
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
p := &staticPool{pkg, name, params}
|
|
|
|
err = pkg.scope.AddPool(p)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *staticPool) pkg() *pkg {
|
|
|
|
return p.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *staticPool) name() string {
|
|
|
|
return p.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *staticPool) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return packageNamespacePrefix(pkgNames[p.pkg_]) + p.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *staticPool) def(config Config) (*poolDef, error) {
|
|
|
|
def, err := parsePoolParams(p.pkg_.scope, &p.params)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("error parsing PoolParams for %s: %s", p.name_, err))
|
|
|
|
}
|
|
|
|
return def, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type poolFunc struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
paramsFunc func(Config) (PoolParams, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func PoolFunc(name string, f func(Config) (PoolParams, error)) Pool {
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
p := &poolFunc{pkg, name, f}
|
|
|
|
err = pkg.scope.AddPool(p)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *poolFunc) pkg() *pkg {
|
|
|
|
return p.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *poolFunc) name() string {
|
|
|
|
return p.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *poolFunc) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return packageNamespacePrefix(pkgNames[p.pkg_]) + p.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *poolFunc) def(config Config) (*poolDef, error) {
|
|
|
|
params, err := p.paramsFunc(config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
def, err := parsePoolParams(p.pkg_.scope, ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("error parsing PoolParams for %s: %s", p.name_, err))
|
|
|
|
}
|
|
|
|
return def, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type staticRule struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
params RuleParams
|
|
|
|
argNames map[string]bool
|
|
|
|
scope_ *scope
|
|
|
|
}
|
|
|
|
|
|
|
|
func StaticRule(name string, params RuleParams, argNames ...string) Rule {
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validateArgNames(argNames)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("invalid argument name: %s", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
argNamesSet := make(map[string]bool)
|
|
|
|
for _, argName := range argNames {
|
|
|
|
argNamesSet[argName] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
ruleScope := (*scope)(nil) // This will get created lazily
|
|
|
|
|
|
|
|
r := &staticRule{pkg, name, params, argNamesSet, ruleScope}
|
|
|
|
err = pkg.scope.AddRule(r)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *staticRule) pkg() *pkg {
|
|
|
|
return r.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *staticRule) name() string {
|
|
|
|
return r.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *staticRule) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return packageNamespacePrefix(pkgNames[r.pkg_]) + r.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *staticRule) def(Config) (*ruleDef, error) {
|
|
|
|
def, err := parseRuleParams(r.scope(), &r.params)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("error parsing RuleParams for %s: %s", r.name_, err))
|
|
|
|
}
|
|
|
|
return def, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *staticRule) scope() *scope {
|
|
|
|
// We lazily create the scope so that all the global variables get declared
|
|
|
|
// before the args are created. Otherwise we could incorrectly shadow a
|
|
|
|
// global variable with an arg variable.
|
|
|
|
if r.scope_ == nil {
|
|
|
|
r.scope_ = makeRuleScope(r.pkg_.scope, r.argNames)
|
|
|
|
}
|
|
|
|
return r.scope_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *staticRule) isArg(argName string) bool {
|
|
|
|
return r.argNames[argName]
|
|
|
|
}
|
|
|
|
|
|
|
|
type ruleFunc struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
paramsFunc func(Config) (RuleParams, error)
|
|
|
|
argNames map[string]bool
|
|
|
|
scope_ *scope
|
|
|
|
}
|
|
|
|
|
|
|
|
func RuleFunc(name string, f func(Config) (RuleParams, error),
|
|
|
|
argNames ...string) Rule {
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
|
|
|
|
err := validateNinjaName(name)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = validateArgNames(argNames)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("invalid argument name: %s", err))
|
|
|
|
}
|
|
|
|
|
|
|
|
argNamesSet := make(map[string]bool)
|
|
|
|
for _, argName := range argNames {
|
|
|
|
argNamesSet[argName] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
ruleScope := (*scope)(nil) // This will get created lazily
|
|
|
|
|
|
|
|
r := &ruleFunc{pkg, name, f, argNamesSet, ruleScope}
|
|
|
|
err = pkg.scope.AddRule(r)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ruleFunc) pkg() *pkg {
|
|
|
|
return r.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ruleFunc) name() string {
|
|
|
|
return r.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ruleFunc) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return packageNamespacePrefix(pkgNames[r.pkg_]) + r.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ruleFunc) def(config Config) (*ruleDef, error) {
|
|
|
|
params, err := r.paramsFunc(config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
def, err := parseRuleParams(r.scope(), ¶ms)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("error parsing RuleParams for %s: %s", r.name_, err))
|
|
|
|
}
|
|
|
|
return def, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ruleFunc) scope() *scope {
|
|
|
|
// We lazily create the scope so that all the global variables get declared
|
|
|
|
// before the args are created. Otherwise we could incorrectly shadow a
|
|
|
|
// global variable with an arg variable.
|
|
|
|
if r.scope_ == nil {
|
|
|
|
r.scope_ = makeRuleScope(r.pkg_.scope, r.argNames)
|
|
|
|
}
|
|
|
|
return r.scope_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *ruleFunc) isArg(argName string) bool {
|
|
|
|
return r.argNames[argName]
|
|
|
|
}
|
|
|
|
|
|
|
|
type builtinRule struct {
|
|
|
|
name_ string
|
|
|
|
scope_ *scope
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *builtinRule) pkg() *pkg {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *builtinRule) name() string {
|
|
|
|
return r.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *builtinRule) fullName(pkgNames map[*pkg]string) string {
|
|
|
|
return r.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *builtinRule) def(config Config) (*ruleDef, error) {
|
|
|
|
return nil, errRuleIsBuiltin
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *builtinRule) scope() *scope {
|
|
|
|
if r.scope_ == nil {
|
|
|
|
r.scope_ = makeRuleScope(nil, nil)
|
|
|
|
}
|
|
|
|
return r.scope_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *builtinRule) isArg(argName string) bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
type ModuleType interface {
|
|
|
|
pkg() *pkg
|
|
|
|
name() string
|
|
|
|
new() (m Module, properties interface{})
|
|
|
|
}
|
|
|
|
|
|
|
|
type moduleTypeFunc struct {
|
|
|
|
pkg_ *pkg
|
|
|
|
name_ string
|
|
|
|
new_ func() (Module, interface{})
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeModuleType(name string,
|
|
|
|
new func() (m Module, properties interface{})) ModuleType {
|
|
|
|
|
|
|
|
pkg := callerPackage()
|
|
|
|
return &moduleTypeFunc{pkg, name, new}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *moduleTypeFunc) pkg() *pkg {
|
|
|
|
return m.pkg_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *moduleTypeFunc) name() string {
|
|
|
|
return m.pkg_.pkgPath + "." + m.name_
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *moduleTypeFunc) new() (Module, interface{}) {
|
|
|
|
return m.new_()
|
|
|
|
}
|