From 7675e057d226c7c945d4a00141b2e132bf1a5aab Mon Sep 17 00:00:00 2001 From: Jason Perkins Date: Thu, 26 Apr 2012 07:44:25 -0400 Subject: [PATCH] Deep copy all object values, to allow unique per-target token expansions --- src/base/table.lua | 28 ++++++++++++++++++++++++++++ src/project/oven.lua | 10 ++++++---- tests/oven/test_tokens.lua | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 4 deletions(-) diff --git a/src/base/table.lua b/src/base/table.lua index 877fa689..63985554 100644 --- a/src/base/table.lua +++ b/src/base/table.lua @@ -18,7 +18,35 @@ return false end + +-- +-- Make a complete copy of a table, including any child tables it contains. +-- + + function table.deepcopy(object) + -- keep track of already seen objects to avoid loops + local seen = {} + local function copy(object) + if type(object) ~= "table" then + return object + elseif seen[object] then + return seen[object] + end + + local clone = {} + seen[object] = clone + for key, value in pairs(object) do + clone[key] = copy(value) + end + + return clone + end + + return copy(object) + end + + -- -- Enumerates an array of objects and returns a new table containing -- only the value of one particular field. diff --git a/src/project/oven.lua b/src/project/oven.lua index 2b53f0cc..6393c4b6 100755 --- a/src/project/oven.lua +++ b/src/project/oven.lua @@ -122,7 +122,6 @@ function oven.expandtokens(cfg, scope, filecfg) -- build a context for the tokens to use local context = { - _G = _G, sln = cfg.solution, prj = cfg.project, cfg = cfg, @@ -163,7 +162,8 @@ -- give the function access to the project objects setfenv(func, context) - + setmetatable(context, {__index = _G}) + -- run it and return the result local result = func() if not result then @@ -395,11 +395,13 @@ -- function oven.mergevalue(target, fieldname, fieldkind, value) - -- list values get merged, others overwrite + -- list values get merged, others overwrite; note that if the + -- values contain tokens they will be modified in the token + -- expansion phase, so important to make copies of objects if fieldkind:endswith("list") then target[fieldname] = oven.mergetables(target[fieldname] or {}, value) else - target[fieldname] = value + target[fieldname] = table.deepcopy(value) end end diff --git a/tests/oven/test_tokens.lua b/tests/oven/test_tokens.lua index a796c35f..a0a317ab 100644 --- a/tests/oven/test_tokens.lua +++ b/tests/oven/test_tokens.lua @@ -85,3 +85,37 @@ local fcfg = config.getfileconfig(cfg, os.getcwd().."/shaders/hello.cg") test.isequal("cgc --profile gp5vp shaders/hello.cg -o obj/Debug/hello.gxp", fcfg.buildrule.commands[1]) end + + +-- +-- Make sure that the same token source can be applied to multiple targets. +-- + + function suite.canReuseTokenSources() + files { "shaders/hello.cg", "shaders/goodbye.cg" } + configuration { "**.cg" } + buildrule { + commands = { + "cgc --profile gp5vp %{file.path} -o %{cfg.objdir}/%{file.basename}.gxp", + }, + outputs = { + "%{cfg.objdir}/%{file.basename}.o" + } + } + prepare() + local fcfg = config.getfileconfig(cfg, os.getcwd().."/shaders/hello.cg") + test.isequal("cgc --profile gp5vp shaders/hello.cg -o obj/Debug/hello.gxp", fcfg.buildrule.commands[1]) + fcfg = config.getfileconfig(cfg, os.getcwd().."/shaders/goodbye.cg") + test.isequal("cgc --profile gp5vp shaders/goodbye.cg -o obj/Debug/goodbye.gxp", fcfg.buildrule.commands[1]) + end + + +-- +-- Verify the global namespace is still accessible. +-- + + function suite.canUseGlobalFunctions() + testapi "%{iif(true, 'a', 'b')}" + prepare() + test.isequal("a", cfg.testapi) + end