Add an 'extended' & 'uncached' sub-context to the context.

Context sensitive detokenization of Visual Studio rules property definitions.
This commit is contained in:
Tom van Dijck 2016-07-29 16:57:41 -07:00
parent 7fc49130ea
commit 7b712d7ce3
4 changed files with 115 additions and 8 deletions

View File

@ -145,7 +145,15 @@
function m.commandLineTemplates(r) function m.commandLineTemplates(r)
if #r.buildcommands then if #r.buildcommands then
local cmds = os.translateCommands(r.buildcommands, p.WINDOWS)
-- create shadow context.
local env = p.rule.createEnvironment(r, "[%s]")
local ctx = p.context.extent(r, env)
-- now use the shadow context to detoken.
local cmds = os.translateCommands(ctx.buildcommands, p.WINDOWS)
-- write out the result.
cmds = table.concat(cmds, p.eol()) cmds = table.concat(cmds, p.eol())
p.x('<CommandLineTemplate>%s</CommandLineTemplate>', cmds) p.x('<CommandLineTemplate>%s</CommandLineTemplate>', cmds)
end end
@ -163,7 +171,12 @@
function m.executionDescription(r) function m.executionDescription(r)
if r.buildmessage then if r.buildmessage then
p.x('<ExecutionDescription>%s</ExecutionDescription>', r.buildmessage) -- create shadow context.
local env = p.rule.createEnvironment(r, "[%s]")
local ctx = p.context.extent(r, env)
-- write out the result.
p.x('<ExecutionDescription>%s</ExecutionDescription>', ctx.buildmessage)
end end
end end
@ -171,7 +184,14 @@
function m.outputs(r) function m.outputs(r)
if #r.buildoutputs then if #r.buildoutputs then
local outputs = table.concat(r.buildoutputs, ";") -- create shadow context.
local pathVars = p.rule.createPathVars(r, "%%(%s)")
local ctx = p.context.extent(r, { pathVars = pathVars })
-- now use the shadow context to detoken.
local outputs = table.concat(ctx.buildoutputs, ";")
-- write out the result.
p.x('<Outputs>%s</Outputs>', path.translate(outputs)) p.x('<Outputs>%s</Outputs>', path.translate(outputs))
end end
end end

View File

@ -59,6 +59,31 @@
end end
--
-- Create an extended and uncached context based on another context object.
--
-- @param baseContext
-- The base context to extent
-- @param newEnvVars
-- An optional key-value environment table for token expansion; keys and
-- values provided in this table will be available for tokens to use.
-- @return
-- A new context object.
--
function context.extent(baseContext, newEnvVars)
local ctx = {}
ctx._ctx = baseContext
ctx.environ = newEnvVars or baseContext.environ
ctx.terms = {}
ctx._basedir = baseContext._basedir
setmetatable(ctx, context.__mt_uncached)
return ctx
end
--- ---
-- Add a new key-value pair to refine the context filtering. -- Add a new key-value pair to refine the context filtering.
@ -204,7 +229,7 @@
local value = configset.fetch(ctx._cfgset, field, ctx.terms, ctx, onlylocal and ctx._cfgset) local value = configset.fetch(ctx._cfgset, field, ctx.terms, ctx, onlylocal and ctx._cfgset)
if value then if value then
-- store the result for later lookups -- store the result for later lookups
ctx[key] = value rawset(ctx, key, value)
end end
return value return value
@ -214,3 +239,14 @@
__index = context.fetchvalue __index = context.fetchvalue
} }
context.__mt_uncached = {
__index = function(ctx, key)
local field = p.field.get(key)
if not field then
return nil
end
local parent = rawget(ctx, '_ctx')
return configset.fetch(parent._cfgset, field, ctx.terms, ctx, nil)
end
}

View File

@ -42,6 +42,9 @@
end end
end end
-- fetch the pathVars from the enviroment.
local envMap = environ.pathVars or {}
-- enable access to the global environment -- enable access to the global environment
setmetatable(environ, {__index = _G}) setmetatable(environ, {__index = _G})
@ -79,14 +82,14 @@
end end
end end
-- If this token is in my path variable mapping table, replace the -- If this token is in my path variable mapping tables, replace the
-- value with the one from the map. This needs to go here because -- value with the one from the map. This needs to go here because
-- I don't want to make the result relative, but I don't want the -- I don't want to make the result relative, but I don't want the
-- absolute path handling below. -- absolute path handling below.
local mapped = envMap[token] or varMap[token]
if varMap[token] then if mapped then
err = nil err = nil
result = varMap[token] result = mapped
if type(result) == "function" then if type(result) == "function" then
success, result = pcall(result, e) success, result = pcall(result, e)
if not success then if not success then

View File

@ -159,3 +159,51 @@
p.api.storeField(fld, value) p.api.storeField(fld, value)
end end
end end
---
-- prepare an environment with the rule properties as global tokens,
-- according to the format specified.
--
-- @param environ
-- The environment table to fill up
-- @param format
-- The formatting to be used, ie "[%s]".
---
function rule.prepareEnvironment(self, environ, format)
for _, def in ipairs(self.propertydefinition) do
environ[def.name] = string.format(format, def.name)
end
end
function rule.createEnvironment(self, format)
local environ = {}
rule.prepareEnvironment(self, environ, format)
return environ
end
---
-- prepare an table of pathVars with the rule properties as global tokens,
-- according to the format specified.
--
-- @param pathVars
-- The pathVars table to fill up
-- @param format
-- The formatting to be used, ie "%%(%s)".
---
function rule.preparePathVars(self, pathVars, format)
for _, def in ipairs(self.propertydefinition) do
pathVars[def.name] = { absolute = true, token = string.format(format, def.name) }
end
end
function rule.createPathVars(self, format)
local pathVars = {}
rule.preparePathVars(self, pathVars, format)
return pathVars
end