Add SingletonContext.Eval to evaluate ninja strings

Our use case is to write out some configuration variables to give to our
legacy build system. But in order to do that, we either need to keep a
Go copy of all of the configuration, and still have all the calls to
convert them to ninja variables, or evaluate our ninja variables.

Change-Id: If9dda305ed41bc8aabe57dd750a74d8b9af1d1a4
diff --git a/context.go b/context.go
index dfe4d37..ca3f919 100644
--- a/context.go
+++ b/context.go
@@ -1846,6 +1846,7 @@
 			context: c,
 			config:  config,
 			scope:   scope,
+			globals: liveGlobals,
 		}
 
 		func() {
diff --git a/singleton_ctx.go b/singleton_ctx.go
index a2d6109..e761e77 100644
--- a/singleton_ctx.go
+++ b/singleton_ctx.go
@@ -44,6 +44,11 @@
 	// set at most one time for a single build, later calls are ignored.
 	SetNinjaBuildDir(pctx PackageContext, value string)
 
+	// Eval takes a string with embedded ninja variables, and returns a string
+	// with all of the variables recursively expanded. Any variables references
+	// are expanded in the scope of the PackageContext.
+	Eval(pctx PackageContext, ninjaStr string) (string, error)
+
 	VisitAllModules(visit func(Module))
 	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
 	VisitDepsDepthFirst(module Module, visit func(Module))
@@ -64,6 +69,7 @@
 	context *Context
 	config  interface{}
 	scope   *localScope
+	globals *liveTracker
 
 	ninjaFileDeps []string
 	errs          []error
@@ -149,6 +155,22 @@
 	s.actionDefs.buildDefs = append(s.actionDefs.buildDefs, def)
 }
 
+func (s *singletonContext) Eval(pctx PackageContext, str string) (string, error) {
+	s.scope.ReparentTo(pctx)
+
+	ninjaStr, err := parseNinjaString(s.scope, str)
+	if err != nil {
+		return "", err
+	}
+
+	err = s.globals.addNinjaStringDeps(ninjaStr)
+	if err != nil {
+		return "", err
+	}
+
+	return ninjaStr.Eval(s.globals.variables)
+}
+
 func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) {
 	s.context.requireNinjaVersion(major, minor, micro)
 }