diff --git a/context.go b/context.go index 1592154..997aeed 100644 --- a/context.go +++ b/context.go @@ -16,6 +16,7 @@ package blueprint import ( "bytes" + "cmp" "context" "crypto/sha256" "encoding/base64" @@ -29,6 +30,7 @@ import ( "reflect" "runtime" "runtime/pprof" + "slices" "sort" "strings" "sync" @@ -100,7 +102,7 @@ type Context struct { allowMissingDependencies bool // set during PrepareBuildActions - pkgNames map[*packageContext]string + nameTracker *nameTracker liveGlobals *liveTracker globalVariables map[Variable]*ninjaString globalPools map[Pool]*poolDef @@ -2741,7 +2743,7 @@ func jsonModuleFromModuleInfo(m *moduleInfo) *JsonModule { return result } -func jsonModuleWithActionsFromModuleInfo(m *moduleInfo) *JsonModule { +func jsonModuleWithActionsFromModuleInfo(m *moduleInfo, nameTracker *nameTracker) *JsonModule { result := &JsonModule{ jsonModuleName: jsonModuleName{ Name: m.Name(), @@ -2758,17 +2760,17 @@ func jsonModuleWithActionsFromModuleInfo(m *moduleInfo) *JsonModule { Inputs: append(append(append( bDef.InputStrings, bDef.ImplicitStrings...), - getNinjaStringsWithNilPkgNames(bDef.Inputs)...), - getNinjaStringsWithNilPkgNames(bDef.Implicits)...), + getNinjaStrings(bDef.Inputs, nameTracker)...), + getNinjaStrings(bDef.Implicits, nameTracker)...), Outputs: append(append(append( bDef.OutputStrings, bDef.ImplicitOutputStrings...), - getNinjaStringsWithNilPkgNames(bDef.Outputs)...), - getNinjaStringsWithNilPkgNames(bDef.ImplicitOutputs)...), + getNinjaStrings(bDef.Outputs, nameTracker)...), + getNinjaStrings(bDef.ImplicitOutputs, nameTracker)...), } if d, ok := bDef.Variables["description"]; ok { - a.Desc = d.Value(nil) + a.Desc = d.Value(nameTracker) } actions = append(actions, a) } @@ -2786,12 +2788,11 @@ func jsonModuleWithActionsFromModuleInfo(m *moduleInfo) *JsonModule { return result } -// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value with -// nil pkgNames on each of the input ninjaStrings. -func getNinjaStringsWithNilPkgNames(nStrs []*ninjaString) []string { +// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value on each. +func getNinjaStrings(nStrs []*ninjaString, nameTracker *nameTracker) []string { var strs []string for _, nstr := range nStrs { - strs = append(strs, nstr.Value(nil)) + strs = append(strs, nstr.Value(nameTracker)) } return strs } @@ -2799,7 +2800,7 @@ func getNinjaStringsWithNilPkgNames(nStrs []*ninjaString) []string { func (c *Context) GetWeightedOutputsFromPredicate(predicate func(*JsonModule) (bool, int)) map[string]int { outputToWeight := make(map[string]int) for _, m := range c.modulesSorted { - jmWithActions := jsonModuleWithActionsFromModuleInfo(m) + jmWithActions := jsonModuleWithActionsFromModuleInfo(m, c.nameTracker) if ok, weight := predicate(jmWithActions); ok { for _, a := range jmWithActions.Module["Actions"].([]JSONAction) { for _, o := range a.Outputs { @@ -2831,7 +2832,7 @@ func (c *Context) PrintJSONGraphAndActions(wGraph io.Writer, wActions io.Writer) modulesToActions := make([]*JsonModule, 0) for _, m := range c.modulesSorted { jm := jsonModuleFromModuleInfo(m) - jmWithActions := jsonModuleWithActionsFromModuleInfo(m) + jmWithActions := jsonModuleWithActionsFromModuleInfo(m, c.nameTracker) for _, d := range m.directDeps { jm.Deps = append(jm.Deps, jsonDep{ jsonModuleName: *jsonModuleNameFromModuleInfo(d.module), @@ -2918,12 +2919,12 @@ func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs [ deps = append(deps, depsPackages...) - c.memoizeFullNames(c.liveGlobals, pkgNames) + nameTracker := c.memoizeFullNames(c.liveGlobals, pkgNames) // This will panic if it finds a problem since it's a programming error. - c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames) + c.checkForVariableReferenceCycles(c.liveGlobals.variables, nameTracker) - c.pkgNames = pkgNames + c.nameTracker = nameTracker c.globalVariables = c.liveGlobals.variables c.globalPools = c.liveGlobals.pools c.globalRules = c.liveGlobals.rules @@ -3862,20 +3863,27 @@ func (c *Context) makeUniquePackageNames( // memoizeFullNames stores the full name of each live global variable, rule and pool since each is // guaranteed to be used at least twice, once in the definition and once for each usage, and many // are used much more than once. -func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) { +func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) *nameTracker { + nameTracker := &nameTracker{ + pkgNames: pkgNames, + variables: make(map[Variable]string), + rules: make(map[Rule]string), + pools: make(map[Pool]string), + } for v := range liveGlobals.variables { - v.memoizeFullName(pkgNames) + nameTracker.variables[v] = v.fullName(pkgNames) } for r := range liveGlobals.rules { - r.memoizeFullName(pkgNames) + nameTracker.rules[r] = r.fullName(pkgNames) } for p := range liveGlobals.pools { - p.memoizeFullName(pkgNames) + nameTracker.pools[p] = p.fullName(pkgNames) } + return nameTracker } func (c *Context) checkForVariableReferenceCycles( - variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) { + variables map[Variable]*ninjaString, nameTracker *nameTracker) { visited := make(map[Variable]bool) // variables that were already checked checking := make(map[Variable]bool) // variables actively being checked @@ -3905,12 +3913,12 @@ func (c *Context) checkForVariableReferenceCycles( msgs := []string{"detected variable reference cycle:"} // Iterate backwards through the cycle list. - curName := v.fullName(pkgNames) - curValue := value.Value(pkgNames) + curName := nameTracker.Variable(v) + curValue := value.Value(nameTracker) for i := len(cycle) - 1; i >= 0; i-- { next := cycle[i] - nextName := next.fullName(pkgNames) - nextValue := variables[next].Value(pkgNames) + nextName := nameTracker.Variable(next) + nextValue := variables[next].Value(nameTracker) msgs = append(msgs, fmt.Sprintf( " %q depends on %q", curName, nextName)) @@ -3958,7 +3966,7 @@ func (c *Context) AllTargets() (map[string]string, error) { targets := map[string]string{} var collectTargets = func(actionDefs localBuildActions) error { for _, buildDef := range actionDefs.buildDefs { - ruleName := buildDef.Rule.fullName(c.pkgNames) + ruleName := c.nameTracker.Rule(buildDef.Rule) for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) { outputValue, err := output.Eval(c.globalVariables) if err != nil { @@ -4266,7 +4274,7 @@ func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error { var pkgs []pkgAssociation maxNameLen := 0 - for pkg, name := range c.pkgNames { + for pkg, name := range c.nameTracker.pkgNames { pkgs = append(pkgs, pkgAssociation{ PkgName: name, PkgPath: pkg.pkgPath, @@ -4319,7 +4327,7 @@ func (c *Context) writeSubninjas(nw *ninjaWriter) error { func (c *Context) writeBuildDir(nw *ninjaWriter) error { if c.outDir != nil { - err := nw.Assign("builddir", c.outDir.Value(c.pkgNames)) + err := nw.Assign("builddir", c.outDir.Value(c.nameTracker)) if err != nil { return err } @@ -4332,29 +4340,6 @@ func (c *Context) writeBuildDir(nw *ninjaWriter) error { return nil } -type globalEntity interface { - fullName(pkgNames map[*packageContext]string) string -} - -type globalEntitySorter struct { - pkgNames map[*packageContext]string - entities []globalEntity -} - -func (s *globalEntitySorter) Len() int { - return len(s.entities) -} - -func (s *globalEntitySorter) Less(i, j int) bool { - iName := s.entities[i].fullName(s.pkgNames) - jName := s.entities[j].fullName(s.pkgNames) - return iName < jName -} - -func (s *globalEntitySorter) Swap(i, j int) { - s.entities[i], s.entities[j] = s.entities[j], s.entities[i] -} - func (c *Context) writeGlobalVariables(nw *ninjaWriter) error { visited := make(map[Variable]bool) @@ -4373,7 +4358,7 @@ func (c *Context) writeGlobalVariables(nw *ninjaWriter) error { } } - err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames)) + err := nw.Assign(c.nameTracker.Variable(v), value.Value(c.nameTracker)) if err != nil { return err } @@ -4386,15 +4371,16 @@ func (c *Context) writeGlobalVariables(nw *ninjaWriter) error { return nil } - globalVariables := make([]globalEntity, 0, len(c.globalVariables)) + globalVariables := make([]Variable, 0, len(c.globalVariables)) for variable := range c.globalVariables { globalVariables = append(globalVariables, variable) } - sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables}) + slices.SortFunc(globalVariables, func(a, b Variable) int { + return cmp.Compare(c.nameTracker.Variable(a), c.nameTracker.Variable(b)) + }) - for _, entity := range globalVariables { - v := entity.(Variable) + for _, v := range globalVariables { if !visited[v] { err := walk(v) if err != nil { @@ -4407,16 +4393,17 @@ func (c *Context) writeGlobalVariables(nw *ninjaWriter) error { } func (c *Context) writeGlobalPools(nw *ninjaWriter) error { - globalPools := make([]globalEntity, 0, len(c.globalPools)) + globalPools := make([]Pool, 0, len(c.globalPools)) for pool := range c.globalPools { globalPools = append(globalPools, pool) } - sort.Sort(&globalEntitySorter{c.pkgNames, globalPools}) + slices.SortFunc(globalPools, func(a, b Pool) int { + return cmp.Compare(c.nameTracker.Pool(a), c.nameTracker.Pool(b)) + }) - for _, entity := range globalPools { - pool := entity.(Pool) - name := pool.fullName(c.pkgNames) + for _, pool := range globalPools { + name := c.nameTracker.Pool(pool) def := c.globalPools[pool] err := def.WriteTo(nw, name) if err != nil { @@ -4433,18 +4420,19 @@ func (c *Context) writeGlobalPools(nw *ninjaWriter) error { } func (c *Context) writeGlobalRules(nw *ninjaWriter) error { - globalRules := make([]globalEntity, 0, len(c.globalRules)) + globalRules := make([]Rule, 0, len(c.globalRules)) for rule := range c.globalRules { globalRules = append(globalRules, rule) } - sort.Sort(&globalEntitySorter{c.pkgNames, globalRules}) + slices.SortFunc(globalRules, func(a, b Rule) int { + return cmp.Compare(c.nameTracker.Rule(a), c.nameTracker.Rule(b)) + }) - for _, entity := range globalRules { - rule := entity.(Rule) - name := rule.fullName(c.pkgNames) + for _, rule := range globalRules { + name := c.nameTracker.Rule(rule) def := c.globalRules[rule] - err := def.WriteTo(nw, name, c.pkgNames) + err := def.WriteTo(nw, name, c.nameTracker) if err != nil { return err } @@ -4766,7 +4754,7 @@ func (c *Context) writeLocalBuildActions(nw *ninjaWriter, if err != nil { panic(err) } - err = nw.Assign(name, value.Value(c.pkgNames)) + err = nw.Assign(name, value.Value(c.nameTracker)) if err != nil { return err } @@ -4789,7 +4777,7 @@ func (c *Context) writeLocalBuildActions(nw *ninjaWriter, panic(err) } - err = def.WriteTo(nw, name, c.pkgNames) + err = def.WriteTo(nw, name, c.nameTracker) if err != nil { return err } @@ -4802,7 +4790,7 @@ func (c *Context) writeLocalBuildActions(nw *ninjaWriter, // Write the build definitions. for _, buildDef := range defs.buildDefs { - err := buildDef.WriteTo(nw, c.pkgNames) + err := buildDef.WriteTo(nw, c.nameTracker) if err != nil { return err } diff --git a/ninja_defs.go b/ninja_defs.go index a1a3124..da02aae 100644 --- a/ninja_defs.go +++ b/ninja_defs.go @@ -229,8 +229,7 @@ func parseRuleParams(scope scope, params *RuleParams) (*ruleDef, return r, nil } -func (r *ruleDef) WriteTo(nw *ninjaWriter, name string, - pkgNames map[*packageContext]string) error { +func (r *ruleDef) WriteTo(nw *ninjaWriter, name string, nameTracker *nameTracker) error { if r.Comment != "" { err := nw.Comment(r.Comment) @@ -245,13 +244,13 @@ func (r *ruleDef) WriteTo(nw *ninjaWriter, name string, } if r.Pool != nil { - err = nw.ScopedAssign("pool", r.Pool.fullName(pkgNames)) + err = nw.ScopedAssign("pool", nameTracker.Pool(r.Pool)) if err != nil { return err } } - err = writeVariables(nw, r.Variables, pkgNames) + err = writeVariables(nw, r.Variables, nameTracker) if err != nil { return err } @@ -415,10 +414,10 @@ func parseBuildParams(scope scope, params *BuildParams, return b, nil } -func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) error { +func (b *buildDef) WriteTo(nw *ninjaWriter, nameTracker *nameTracker) error { var ( comment = b.Comment - rule = b.Rule.fullName(pkgNames) + rule = nameTracker.Rule(b.Rule) outputs = b.Outputs implicitOuts = b.ImplicitOutputs explicitDeps = b.Inputs @@ -441,12 +440,12 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) err := nw.Build(comment, rule, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps, validations, outputStrings, implicitOutStrings, explicitDepStrings, implicitDepStrings, orderOnlyDepStrings, validationStrings, - pkgNames) + nameTracker) if err != nil { return err } - err = writeVariables(nw, b.Variables, pkgNames) + err = writeVariables(nw, b.Variables, nameTracker) if err != nil { return err } @@ -458,8 +457,8 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) args := make([]nameValuePair, 0, len(b.Args)) for argVar, value := range b.Args { - fullName := argVar.fullName(pkgNames) - args = append(args, nameValuePair{fullName, value.Value(pkgNames)}) + fullName := nameTracker.Variable(argVar) + args = append(args, nameValuePair{fullName, value.Value(nameTracker)}) } sort.Slice(args, func(i, j int) bool { return args[i].name < args[j].name }) @@ -471,7 +470,7 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) } if !b.Optional { - err = nw.Default(pkgNames, outputs, outputStrings) + err = nw.Default(nameTracker, outputs, outputStrings) if err != nil { return err } @@ -480,8 +479,7 @@ func (b *buildDef) WriteTo(nw *ninjaWriter, pkgNames map[*packageContext]string) return nw.BlankLine() } -func writeVariables(nw *ninjaWriter, variables map[string]*ninjaString, - pkgNames map[*packageContext]string) error { +func writeVariables(nw *ninjaWriter, variables map[string]*ninjaString, nameTracker *nameTracker) error { var keys []string for k := range variables { keys = append(keys, k) @@ -489,7 +487,7 @@ func writeVariables(nw *ninjaWriter, variables map[string]*ninjaString, sort.Strings(keys) for _, name := range keys { - err := nw.ScopedAssign(name, variables[name].Value(pkgNames)) + err := nw.ScopedAssign(name, variables[name].Value(nameTracker)) if err != nil { return err } diff --git a/ninja_strings.go b/ninja_strings.go index 78368ac..8576eae 100644 --- a/ninja_strings.go +++ b/ninja_strings.go @@ -324,17 +324,16 @@ func parseNinjaOrSimpleStrings(scope scope, strs []string) ([]*ninjaString, []st return ninjaStrings, simpleStrings, nil } -func (n *ninjaString) Value(pkgNames map[*packageContext]string) string { +func (n *ninjaString) Value(nameTracker *nameTracker) string { if n.variables == nil || len(*n.variables) == 0 { return defaultEscaper.Replace(n.str) } str := &strings.Builder{} - n.ValueWithEscaper(str, pkgNames, defaultEscaper) + n.ValueWithEscaper(str, nameTracker, defaultEscaper) return str.String() } -func (n *ninjaString) ValueWithEscaper(w io.StringWriter, pkgNames map[*packageContext]string, - escaper *strings.Replacer) { +func (n *ninjaString) ValueWithEscaper(w io.StringWriter, nameTracker *nameTracker, escaper *strings.Replacer) { if n.variables == nil || len(*n.variables) == 0 { w.WriteString(escaper.Replace(n.str)) @@ -348,7 +347,7 @@ func (n *ninjaString) ValueWithEscaper(w io.StringWriter, pkgNames map[*packageC w.WriteString("$ ") } else { w.WriteString("${") - w.WriteString(v.variable.fullName(pkgNames)) + w.WriteString(nameTracker.Variable(v.variable)) w.WriteString("}") } i = int(v.end) diff --git a/ninja_strings_test.go b/ninja_strings_test.go index 8669e60..50a80fa 100644 --- a/ninja_strings_test.go +++ b/ninja_strings_test.go @@ -164,7 +164,7 @@ func TestParseNinjaString(t *testing.T) { output, err := parseNinjaString(scope, testCase.input) if err == nil { - if g, w := output.Value(nil), testCase.value; g != w { + if g, w := output.Value(&nameTracker{}), testCase.value; g != w { t.Errorf("incorrect Value output, want %q, got %q", w, g) } @@ -191,7 +191,11 @@ func TestParseNinjaString(t *testing.T) { } func TestParseNinjaStringWithImportedVar(t *testing.T) { - ImpVar := &staticVariable{name_: "ImpVar", fullName_: "g.impPkg.ImpVar"} + pctx := &packageContext{} + pkgNames := map[*packageContext]string{ + pctx: "impPkg", + } + ImpVar := &staticVariable{pctx: pctx, name_: "ImpVar"} impScope := newScope(nil) impScope.AddVariable(ImpVar) scope := newScope(nil) @@ -211,7 +215,7 @@ func TestParseNinjaStringWithImportedVar(t *testing.T) { t.Errorf(" got: %#v", *output.variables) } - if g, w := output.Value(nil), "abc def ${g.impPkg.ImpVar} ghi"; g != w { + if g, w := output.Value(&nameTracker{pkgNames: pkgNames}), "abc def ${g.impPkg.ImpVar} ghi"; g != w { t.Errorf("incorrect Value output, want %q got %q", w, g) } } @@ -289,7 +293,7 @@ func Test_parseNinjaOrSimpleStrings(t *testing.T) { if gotNinjaStrings != nil { evaluatedNinjaStrings = make([]string, 0, len(gotNinjaStrings)) for _, ns := range gotNinjaStrings { - evaluatedNinjaStrings = append(evaluatedNinjaStrings, ns.Value(nil)) + evaluatedNinjaStrings = append(evaluatedNinjaStrings, ns.Value(&nameTracker{})) } } @@ -364,7 +368,7 @@ func BenchmarkNinjaString_Value(b *testing.B) { b.Run(strconv.Itoa(l), func(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { - ns.Value(nil) + ns.Value(&nameTracker{}) } }) } @@ -377,7 +381,7 @@ func BenchmarkNinjaString_Value(b *testing.B) { b.Run(strconv.Itoa(l), func(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { - ns.Value(nil) + ns.Value(&nameTracker{}) } }) } @@ -394,7 +398,7 @@ func BenchmarkNinjaString_Value(b *testing.B) { b.Run(strconv.Itoa(l), func(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { - ns.Value(nil) + ns.Value(&nameTracker{}) } }) } diff --git a/ninja_writer.go b/ninja_writer.go index 11dd0d0..07acdce 100644 --- a/ninja_writer.go +++ b/ninja_writer.go @@ -117,7 +117,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, explicitDeps, implicitDeps, orderOnlyDeps, validations []*ninjaString, outputStrings, implicitOutStrings, explicitDepStrings, implicitDepStrings, orderOnlyDepStrings, validationStrings []string, - pkgNames map[*packageContext]string) error { + nameTracker *nameTracker) error { n.justDidBlankLine = false @@ -144,7 +144,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } for _, output := range outputs { wrapper.Space() - output.ValueWithEscaper(wrapper, pkgNames, outputEscaper) + output.ValueWithEscaper(wrapper, nameTracker, outputEscaper) } if len(implicitOuts) > 0 || len(implicitOutStrings) > 0 { @@ -156,7 +156,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } for _, out := range implicitOuts { wrapper.Space() - out.ValueWithEscaper(wrapper, pkgNames, outputEscaper) + out.ValueWithEscaper(wrapper, nameTracker, outputEscaper) } } @@ -170,7 +170,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } for _, dep := range explicitDeps { wrapper.Space() - dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper) + dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper) } if len(implicitDeps) > 0 || len(implicitDepStrings) > 0 { @@ -182,7 +182,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } for _, dep := range implicitDeps { wrapper.Space() - dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper) + dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper) } } @@ -195,7 +195,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } for _, dep := range orderOnlyDeps { wrapper.Space() - dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper) + dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper) } } @@ -208,7 +208,7 @@ func (n *ninjaWriter) Build(comment string, rule string, outputs, implicitOuts, } for _, dep := range validations { wrapper.Space() - dep.ValueWithEscaper(wrapper, pkgNames, inputEscaper) + dep.ValueWithEscaper(wrapper, nameTracker, inputEscaper) } } @@ -261,7 +261,7 @@ func (n *ninjaWriter) ScopedAssign(name, value string) error { return nil } -func (n *ninjaWriter) Default(pkgNames map[*packageContext]string, targets []*ninjaString, targetStrings []string) error { +func (n *ninjaWriter) Default(nameTracker *nameTracker, targets []*ninjaString, targetStrings []string) error { n.justDidBlankLine = false const lineWrapLen = len(" $") @@ -280,7 +280,7 @@ func (n *ninjaWriter) Default(pkgNames map[*packageContext]string, targets []*ni } for _, target := range targets { wrapper.Space() - target.ValueWithEscaper(wrapper, pkgNames, outputEscaper) + target.ValueWithEscaper(wrapper, nameTracker, outputEscaper) } return wrapper.Flush() diff --git a/package_ctx.go b/package_ctx.go index 4b48337..db43bec 100644 --- a/package_ctx.go +++ b/package_ctx.go @@ -250,10 +250,9 @@ func (p *packageContext) ImportAs(as, pkgPath string) { } type staticVariable struct { - pctx *packageContext - name_ string - value_ string - fullName_ string + pctx *packageContext + name_ string + value_ string } // StaticVariable returns a Variable whose value does not depend on any @@ -294,16 +293,9 @@ func (v *staticVariable) name() string { } func (v *staticVariable) fullName(pkgNames map[*packageContext]string) string { - if v.fullName_ != "" { - return v.fullName_ - } return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ } -func (v *staticVariable) memoizeFullName(pkgNames map[*packageContext]string) { - v.fullName_ = v.fullName(pkgNames) -} - func (v *staticVariable) value(VariableFuncContext, interface{}) (*ninjaString, error) { ninjaStr, err := parseNinjaString(v.pctx.scope, v.value_) if err != nil { @@ -318,10 +310,9 @@ func (v *staticVariable) String() string { } type variableFunc struct { - pctx *packageContext - name_ string - value_ func(VariableFuncContext, interface{}) (string, error) - fullName_ string + pctx *packageContext + name_ string + value_ func(VariableFuncContext, interface{}) (string, error) } // VariableFuncContext is passed to VariableFunc functions. @@ -430,16 +421,9 @@ func (v *variableFunc) name() string { } func (v *variableFunc) fullName(pkgNames map[*packageContext]string) string { - if v.fullName_ != "" { - return v.fullName_ - } return packageNamespacePrefix(pkgNames[v.pctx]) + v.name_ } -func (v *variableFunc) memoizeFullName(pkgNames map[*packageContext]string) { - v.fullName_ = v.fullName(pkgNames) -} - func (v *variableFunc) value(ctx VariableFuncContext, config interface{}) (*ninjaString, error) { value, err := v.value_(ctx, config) if err != nil { @@ -500,10 +484,6 @@ func (v *argVariable) fullName(pkgNames map[*packageContext]string) string { return v.name_ } -func (v *argVariable) memoizeFullName(pkgNames map[*packageContext]string) { - // Nothing to do, full name is known at initialization. -} - func (v *argVariable) value(ctx VariableFuncContext, config interface{}) (*ninjaString, error) { return nil, errVariableIsArg } @@ -513,10 +493,9 @@ func (v *argVariable) String() string { } type staticPool struct { - pctx *packageContext - name_ string - params PoolParams - fullName_ string + pctx *packageContext + name_ string + params PoolParams } // StaticPool returns a Pool whose value does not depend on any configuration @@ -558,16 +537,9 @@ func (p *staticPool) name() string { } func (p *staticPool) fullName(pkgNames map[*packageContext]string) string { - if p.fullName_ != "" { - return p.fullName_ - } return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ } -func (p *staticPool) memoizeFullName(pkgNames map[*packageContext]string) { - p.fullName_ = p.fullName(pkgNames) -} - func (p *staticPool) def(config interface{}) (*poolDef, error) { def, err := parsePoolParams(p.pctx.scope, &p.params) if err != nil { @@ -584,7 +556,6 @@ type poolFunc struct { pctx *packageContext name_ string paramsFunc func(interface{}) (PoolParams, error) - fullName_ string } // PoolFunc returns a Pool whose value is determined by a function that takes a @@ -629,16 +600,9 @@ func (p *poolFunc) name() string { } func (p *poolFunc) fullName(pkgNames map[*packageContext]string) string { - if p.fullName_ != "" { - return p.fullName_ - } return packageNamespacePrefix(pkgNames[p.pctx]) + p.name_ } -func (p *poolFunc) memoizeFullName(pkgNames map[*packageContext]string) { - p.fullName_ = p.fullName(pkgNames) -} - func (p *poolFunc) def(config interface{}) (*poolDef, error) { params, err := p.paramsFunc(config) if err != nil { @@ -671,10 +635,6 @@ func (p *builtinPool) fullName(pkgNames map[*packageContext]string) string { return p.name_ } -func (p *builtinPool) memoizeFullName(pkgNames map[*packageContext]string) { - // Nothing to do, full name is known at initialization. -} - func (p *builtinPool) def(config interface{}) (*poolDef, error) { return nil, errPoolIsBuiltin } @@ -696,7 +656,6 @@ type staticRule struct { params RuleParams argNames map[string]bool scope_ *basicScope - fullName_ string sync.Mutex // protects scope_ during lazy creation } @@ -764,16 +723,9 @@ func (r *staticRule) name() string { } func (r *staticRule) fullName(pkgNames map[*packageContext]string) string { - if r.fullName_ != "" { - return r.fullName_ - } return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ } -func (r *staticRule) memoizeFullName(pkgNames map[*packageContext]string) { - r.fullName_ = r.fullName(pkgNames) -} - func (r *staticRule) def(interface{}) (*ruleDef, error) { def, err := parseRuleParams(r.scope(), &r.params) if err != nil { @@ -809,7 +761,6 @@ type ruleFunc struct { paramsFunc func(interface{}) (RuleParams, error) argNames map[string]bool scope_ *basicScope - fullName_ string sync.Mutex // protects scope_ during lazy creation } @@ -878,16 +829,9 @@ func (r *ruleFunc) name() string { } func (r *ruleFunc) fullName(pkgNames map[*packageContext]string) string { - if r.fullName_ != "" { - return r.fullName_ - } return packageNamespacePrefix(pkgNames[r.pctx]) + r.name_ } -func (r *ruleFunc) memoizeFullName(pkgNames map[*packageContext]string) { - r.fullName_ = r.fullName(pkgNames) -} - func (r *ruleFunc) def(config interface{}) (*ruleDef, error) { params, err := r.paramsFunc(config) if err != nil { @@ -939,10 +883,6 @@ func (r *builtinRule) fullName(pkgNames map[*packageContext]string) string { return r.name_ } -func (r *builtinRule) memoizeFullName(pkgNames map[*packageContext]string) { - // Nothing to do, full name is known at initialization. -} - func (r *builtinRule) def(config interface{}) (*ruleDef, error) { return nil, errRuleIsBuiltin } diff --git a/scope.go b/scope.go index 0ca3464..95fde6d 100644 --- a/scope.go +++ b/scope.go @@ -28,7 +28,6 @@ type Variable interface { packageContext() *packageContext name() string // "foo" fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo" - memoizeFullName(pkgNames map[*packageContext]string) // precompute fullName if desired value(ctx VariableFuncContext, config interface{}) (*ninjaString, error) String() string } @@ -39,7 +38,6 @@ type Pool interface { packageContext() *packageContext name() string // "foo" fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo" - memoizeFullName(pkgNames map[*packageContext]string) // precompute fullName if desired def(config interface{}) (*poolDef, error) String() string } @@ -50,7 +48,6 @@ type Rule interface { packageContext() *packageContext name() string // "foo" fullName(pkgNames map[*packageContext]string) string // "pkg.foo" or "path.to.pkg.foo" - memoizeFullName(pkgNames map[*packageContext]string) // precompute fullName if desired def(config interface{}) (*ruleDef, error) scope() *basicScope isArg(argName string) bool @@ -369,10 +366,6 @@ func (l *localVariable) fullName(pkgNames map[*packageContext]string) string { return l.fullName_ } -func (l *localVariable) memoizeFullName(pkgNames map[*packageContext]string) { - // Nothing to do, full name is known at initialization. -} - func (l *localVariable) value(VariableFuncContext, interface{}) (*ninjaString, error) { return l.value_, nil } @@ -401,10 +394,6 @@ func (l *localRule) fullName(pkgNames map[*packageContext]string) string { return l.fullName_ } -func (l *localRule) memoizeFullName(pkgNames map[*packageContext]string) { - // Nothing to do, full name is known at initialization. -} - func (l *localRule) def(interface{}) (*ruleDef, error) { return l.def_, nil } @@ -420,3 +409,41 @@ func (r *localRule) isArg(argName string) bool { func (r *localRule) String() string { return ":" + r.fullName_ } + +type nameTracker struct { + variables map[Variable]string + rules map[Rule]string + pools map[Pool]string + + pkgNames map[*packageContext]string +} + +func (m *nameTracker) Variable(v Variable) string { + if m == nil { + return v.fullName(nil) + } + if name, ok := m.variables[v]; ok { + return name + } + return v.fullName(m.pkgNames) +} + +func (m *nameTracker) Rule(r Rule) string { + if m == nil { + return r.fullName(nil) + } + if name, ok := m.rules[r]; ok { + return name + } + return r.fullName(m.pkgNames) +} + +func (m *nameTracker) Pool(p Pool) string { + if m == nil { + return p.fullName(nil) + } + if name, ok := m.pools[p]; ok { + return name + } + return p.fullName(m.pkgNames) +}