From 008bee9871b7ffe6b8bb888b65a0d4524b8568e7 Mon Sep 17 00:00:00 2001 From: William Deegan Date: Fri, 16 Mar 2018 19:19:11 -0400 Subject: Move callable evaluation from EnvironmentValue to EnvironmentValues. Handle simple callable function substitution --- src/engine/SCons/EnvironmentValue.py | 32 +--------- src/engine/SCons/EnvironmentValues.py | 93 +++++++++++++++++++++--------- src/engine/SCons/EnvironmentValuesTests.py | 14 ++--- 3 files changed, 73 insertions(+), 66 deletions(-) diff --git a/src/engine/SCons/EnvironmentValue.py b/src/engine/SCons/EnvironmentValue.py index b5f64cc..ab284ca 100644 --- a/src/engine/SCons/EnvironmentValue.py +++ b/src/engine/SCons/EnvironmentValue.py @@ -379,7 +379,7 @@ class EnvironmentValue(object): if callable(all_values[key].value): t = ValueTypes.CALLABLE else: - t = ValueTypes.VARIABLE + t = ValueTypes.VARIABLE_OR_CALLABLE debug("Now :%s -> (%s/%s/%s)",key,ValueTypes.enum_name(t),v,i) @@ -408,35 +408,5 @@ class EnvironmentValue(object): return retval - def eval_callable(self, to_call, parsed_values, string_values, - target=None, source=None, gvars={}, lvars={}, for_sig=False): - """ - Evaluate a callable and return the generated string. - (Note we'll need to handle recursive expansion) - :param to_call: The callable to call.. - :param gvars: - :param lvars: - :return: - """ - - if 'TARGET' not in lvars: - d = self.create_local_var_dict(target, source) - if d: - lvars = lvars.copy() - lvars.update(d) - - try: - s = to_call(target=lvars['TARGETS'], - source=lvars['SOURCES'], - env=gvars, - for_signature=for_sig) - except TypeError as e: - # TODO: Handle conv/convert parameters... - s = str(to_call) - raise Exception("Not handled eval_callable not normal params") - - # TODO: Now we should ensure the value from callable is then substituted as it can return $XYZ.. - - return s diff --git a/src/engine/SCons/EnvironmentValues.py b/src/engine/SCons/EnvironmentValues.py index 6c43898..285593e 100644 --- a/src/engine/SCons/EnvironmentValues.py +++ b/src/engine/SCons/EnvironmentValues.py @@ -326,36 +326,41 @@ class EnvironmentValues(object): call_value = self.eval_callable(to_call, parsed_values, string_values, target=target, source=source, gvars=gvars, lvars=lvars, for_sig=for_signature) - # TODO: Handle return value not being a string, (a collection for example) - - if is_String(call_value) and '$' not in call_value: - string_values[i] = (call_value, ValueTypes.STRING) - elif is_Sequence(call_value): - # TODO: Handle if need to put back in parsed_values.. (check for $ in any element) - # and/or call subst.. - string_values[i] = (" ".join(call_value), ValueTypes.STRING) - part_string_value = [] - for part in call_value: - if is_String(part) and '$' not in part: - part_string_value.append(part) - else: - try: - part_string_value.append(self[part].subst(env, mode, target, source, gvars, - lvars, conv)) - except KeyError as e: - ev = EnvironmentValue(call_value) - string_values[i] = ( - ev.subst(env, mode, target, source, gvars, lvars, conv), ValueTypes.STRING) + value = EnvironmentValue.factory(call_value) + # Now use value.var_type to decide how to proceed. + if value.var_type == ValueTypes.NUMBER: + string_values[i] = (value, ValueTypes.NUMBER) + parsed_values[i] = None + elif value.var_type == ValueTypes.STRING: + if value[0] == '$' and value[1:] == v: + # Special case, variables value references itself and only itself + string_values[i] = ('', ValueTypes.STRING) + parsed_values[i] = None + else: + string_values[i] = (value.value, ValueTypes.STRING) + parsed_values[i] = None else: - # Returned value has a $ in it. - try: - string_values[i] = env[call_value].subst(env, mode, target, source, gvars, lvars, conv) - except KeyError as e: - ev = EnvironmentValue(call_value) - string_values[i] = (ev.subst(env, mode, target, source, gvars, lvars, conv), ValueTypes.STRING) + # TODO: Handle other recursive loops by empty stringing this value before recursing with copy of lvar? + # TODO: This should insert the return values into the arrays at the current position, not be a string + print("Here") + # string_values[i] = (self.subst(v, self, mode, target, source, gvars, lvars, conv), + # ValueTypes.STRING) + parsed_values[i:i + 1] = value.all_dependencies + string_values[i:i + 1] = [None] * len(value.all_dependencies) + + # now update the rest of parsed_values with new index numbers + parsed_values = [(pn, tn, ii) for (ii, (pn, tn, ix)) in enumerate(parsed_values)] + + # # TODO: Handle return value not being a string, (a collection for example) + # + # if is_String(call_value) and '$' not in call_value: + # string_values[i] = (call_value, ValueTypes.STRING) + # elif is_Sequence(call_value): + # # TODO: Handle if need to put back in parsed_values.. (check for $ in any element) + # # and/or call subst.. + - parsed_values[i] = None elif t == ValueTypes.NUMBER: # yields single value @@ -403,7 +408,39 @@ class EnvironmentValues(object): else: # SHOULD NEVER GET HERE. Drop into debugger if so. debug("AAHAHAHHAH BROKEN") - import pdb; pdb.set_trace() + # import pdb; pdb.set_trace() + + + def eval_callable(self, to_call, parsed_values, string_values, + target=None, source=None, gvars={}, lvars={}, for_sig=False): + """ + Evaluate a callable and return the generated string. + (Note we'll need to handle recursive expansion) + :param to_call: The callable to call.. + :param gvars: + :param lvars: + :return: + """ + + if 'TARGET' not in lvars: + d = self.create_local_var_dict(target, source) + if d: + lvars = lvars.copy() + lvars.update(d) + + try: + s = to_call(target=lvars['TARGETS'], + source=lvars['SOURCES'], + env=gvars, + for_signature=for_sig) + except TypeError as e: + # TODO: Handle conv/convert parameters... + s = str(to_call) + raise Exception("Not handled eval_callable not normal params") + + # TODO: Now we should ensure the value from callable is then substituted as it can return $XYZ.. + + return s @staticmethod def subst(substString, env, mode=0, target=None, source=None, gvars={}, lvars={}, conv=None): diff --git a/src/engine/SCons/EnvironmentValuesTests.py b/src/engine/SCons/EnvironmentValuesTests.py index ee445b0..19ca92f 100644 --- a/src/engine/SCons/EnvironmentValuesTests.py +++ b/src/engine/SCons/EnvironmentValuesTests.py @@ -104,7 +104,7 @@ class TestEnvironmentValues(unittest.TestCase): # Now try getting for signature which should skip escaped part of string xxx_sig = env.subst('$XXX', env, mode=SubstModes.FOR_SIGNATURE) - self.assertEqual(xxx_sig, 'One', "Should have been 'One' Was '%s'"%xxx) # Should we have trailing space? + self.assertEqual(xxx_sig, 'One', "Should have been 'One' Was '%s'"%xxx_sig) # Should we have trailing space? def test_simple_callable_function(self): def foo(target, source, env, for_signature): @@ -142,29 +142,29 @@ class TestEnvironmentValues(unittest.TestCase): env = EnvironmentValues(X='One', XX='Two', XXX='$X $($XX$)') # vanilla string should equal itself - x = env.subst('X', env) + x = env.subst('$X', env) self.assertEqual(x, 'One') env['Y'] = '$X' - xxx = env.subst('XXX', env) + xxx = env.subst('$XXX', env) # Change the value to XX and make sure the value of XXX # changed env['XX'] = 'BLAH' - xxx_2 = env.subst('XXX', env) + xxx_2 = env.subst('$XXX', env) self.assertNotEqual(xxx, xxx_2) - self.assertEqual(xxx_2, "One BLAH") + self.assertEqual(xxx_2, "One BLAH", "Should have been 'One BLAH' Was '%s'"%xxx_2) # now set XX to a function and verify that the value changed # and that the value is correct with the new function def foo(target, source, env, for_signature): return "bar" env['XX'] = foo - xxx_3 = env.subst('XXX', env) + xxx_3 = env.subst('$XXX', env) # print("1:%s 2:%s 3:%s"%(xxx, xxx_2, xxx_3)) self.assertNotEqual(xxx_3, xxx_2) - self.assertEqual(xxx_3, 'One bar') + self.assertEqual(xxx_3, 'One bar', "Should have been 'One bar' Was '%s'"%xxx_3) if __name__ == '__main__': -- cgit v0.12