diff options
-rw-r--r-- | pym/portage/dep/__init__.py | 38 | ||||
-rw-r--r-- | pym/portage/tests/dep/test_paren_reduce.py | 10 |
2 files changed, 38 insertions, 10 deletions
diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py index ecce5d0c5..5b0473389 100644 --- a/pym/portage/dep/__init__.py +++ b/pym/portage/dep/__init__.py @@ -109,7 +109,7 @@ def paren_reduce(mystr): level = 0 stack = [[]] need_bracket = False - + for token in mysplit: if token == "(": need_bracket = False @@ -122,22 +122,46 @@ def paren_reduce(mystr): if level > 0: level -= 1 l = stack.pop() + is_single = (len(l) == 1 or (len(l)==2 and (l[0] == "||" or l[0][-1] == "?"))) + + def ends_in_any_of_dep(k): + return k>=0 and stack[k] and stack[k][-1] == "||" + + def ends_in_operator(k): + return k>=0 and stack[k] and (stack[k][-1] == "||" or stack[k][-1][-1] == "?") + + def special_append(): + """ + Use extend instead of append if possible. This kills all redundant brackets. + """ + if is_single and (not stack[level] or not stack[level][-1][-1] == "?"): + if len(l) == 1 and isinstance(l[0], list): + # l = [[...]] + stack[level].extend(l[0]) + else: + stack[level].extend(l) + else: + stack[level].append(l) + if l: - if not stack[level] or (stack[level][-1] != "||" and not stack[level][-1][-1] == "?"): - #Optimize: ( ( ... ) ) -> ( ... ) + if not ends_in_any_of_dep(level-1) and not ends_in_operator(level): + #Optimize: ( ( ... ) ) -> ( ... ). Make sure there is no '||' hanging around. stack[level].extend(l) - elif len(l) == 1 and stack[level][-1] == "||": + elif not stack[level]: + #An '||' in the level above forces us to keep to brackets. + special_append() + elif len(l) == 1 and ends_in_any_of_dep(level): #Optimize: || ( A ) -> A stack[level].pop() - stack[level].extend(l) + special_append() elif len(l) == 2 and (l[0] == "||" or l[0][-1] == "?") and stack[level][-1] in (l[0], "||"): #Optimize: || ( || ( ... ) ) -> || ( ... ) # foo? ( foo? ( ... ) ) -> foo? ( ... ) # || ( foo? ( ... ) ) -> foo? ( ... ) stack[level].pop() - stack[level].extend(l) + special_append() else: - stack[level].append(l) + special_append() else: if stack[level] and (stack[level][-1] == "||" or stack[level][-1][-1] == "?"): stack[level].pop() diff --git a/pym/portage/tests/dep/test_paren_reduce.py b/pym/portage/tests/dep/test_paren_reduce.py index bd5f42584..6aac955c5 100644 --- a/pym/portage/tests/dep/test_paren_reduce.py +++ b/pym/portage/tests/dep/test_paren_reduce.py @@ -18,8 +18,7 @@ class TestParenReduce(TestCase): ( "|| ( A || ( B || ( C D ) E ) )", [ "||", ["A", "||", ["B", "||", ["C", "D"], "E"]] ]), ( "a? ( A )", ["a?", ["A"]]), - ( "( || ( ( ( A ) B ) ) )", [ "||", ["A", "B"] ]), - ( "( || ( || ( ( A ) B ) ) )", [ "||", ["A", "B"] ]), + ( "( || ( ( ( A ) B ) ) )", ["A", "B"]), ( "( || ( || ( ( A ) B ) ) )", [ "||", ["A", "B"] ]), ( "|| ( A )", ["A"]), ( "( || ( || ( || ( A ) foo? ( B ) ) ) )", [ "||", ["A", "foo?", ["B"] ]]), @@ -28,6 +27,9 @@ class TestParenReduce(TestCase): ( "|| ( A ) || ( B )", ["A", "B"]), ( "foo? ( A ) foo? ( B )", ["foo?", ["A"], "foo?", ["B"]]), + + ( "|| ( ( A B ) C )", [ "||", [ ["A", "B"], "C"] ]), + ( "|| ( ( A B ) ( C ) )", [ "||", [ ["A", "B"], "C"] ]), ) test_cases_xfail = ( @@ -53,7 +55,9 @@ class TestParenReduce(TestCase): ) for dep_str, expected_result in test_cases: - self.assertEqual(paren_reduce(dep_str), expected_result) + self.assertEqual(paren_reduce(dep_str), expected_result, + "input: '%s' result: %s != %s" % (dep_str, + paren_reduce(dep_str), expected_result)) for dep_str in test_cases_xfail: self.assertRaisesMsg(dep_str, |