use_reduce: Fully reduce complex || constructs.
authorSebastian Luther <SebastianLuther@gmx.de>
Fri, 15 Oct 2010 08:11:00 +0000 (10:11 +0200)
committerZac Medico <zmedico@gentoo.org>
Fri, 15 Oct 2010 08:17:11 +0000 (01:17 -0700)
This will fix bug 340973.

pym/portage/dep/__init__.py
pym/portage/tests/dep/test_use_reduce.py

index 4de9c8422a59ef32068df0730fe530bc92a8619f..da67dd1fe11c5effc1f095a8ea66f4654bc323e8 100644 (file)
@@ -378,7 +378,10 @@ def use_reduce(depstr, uselist=[], masklist=[], matchall=False, excludeall=[], i
                        if level > 0:
                                level -= 1
                                l = stack.pop()
-                               is_single = (len(l) == 1 or (len(l)==2 and l[0] == "||"))
+
+                               is_single = len(l) == 1 or \
+                                       (opconvert and l and l[0] == "||") or \
+                                       (not opconvert and len(l)==2 and l[0] == "||")
                                ignore = False
 
                                if flat:
@@ -411,17 +414,45 @@ def use_reduce(depstr, uselist=[], masklist=[], matchall=False, excludeall=[], i
                                def ends_in_any_of_dep(k):
                                        return k>=0 and stack[k] and stack[k][-1] == "||"
 
+                               def starts_with_any_of_dep(k):
+                                       #'ends_in_any_of_dep' for opconvert
+                                       return k>=0 and stack[k] and stack[k][0] == "||"
+
+                               def last_any_of_operator_level(k):
+                                       #Returns the level of the last || operator if it is ineffect for
+                                       #the current level. It is not in effect, if there is a level, that
+                                       #ends in a non-operator. This is almost equivalent to stack[level][-1]=="||",
+                                       #expect that it skips empty levels.
+                                       while k>=0:
+                                               if stack[k]:
+                                                       if stack[k][-1] == "||":
+                                                               return k
+                                                       elif stack[k][-1][-1] != "?":
+                                                               return -1
+                                               k -= 1
+                                       return -1
+
                                def special_append():
                                        """
                                        Use extend instead of append if possible. This kills all redundant brackets.
                                        """
                                        if is_single:
-                                               if len(l) == 1 and isinstance(l[0], list):
+                                               #Either [A], [[...]] or [|| [...]]
+                                               if l[0] == "||" and ends_in_any_of_dep(level-1):
+                                                       if opconvert:
+                                                               stack[level].extend(l[1:])
+                                                       else:
+                                                               stack[level].extend(l[1])
+                                               elif len(l) == 1 and isinstance(l[0], list):
                                                        # l = [[...]]
-                                                       stack[level].extend(l[0])
+                                                       last = last_any_of_operator_level(level)
+                                                       if last == -1:
+                                                               stack[level].extend(l[0])
+                                                       else:
+                                                               stack[level].append(l[0])
                                                else:
                                                        stack[level].extend(l)
-                                       else:   
+                                       else:
                                                stack[level].append(l)
 
                                if l and not ignore:
@@ -437,15 +468,16 @@ def use_reduce(depstr, uselist=[], masklist=[], matchall=False, excludeall=[], i
                                                #Optimize: || ( A ) -> A,  || ( || ( ... ) ) -> || ( ... )
                                                stack[level].pop()
                                                special_append()
+                                       elif ends_in_any_of_dep(level) and ends_in_any_of_dep(level-1):
+                                               #Optimize: || ( A || ( B C ) ) -> || ( A B C )
+                                               stack[level].pop()
+                                               stack[level].extend(l)
                                        else:
-                                               if opconvert and ends_in_any_of_dep(level):
+                                               if opconvert and starts_with_any_of_dep(level):
                                                        #In opconvert mode, we have to move the operator from the level
                                                        #above into the current list.
-                                                       if l[0] == '||':
-                                                               stack[level].extend(l[1:])
-                                                       else:
-                                                               stack[level].pop()
-                                                               stack[level].append(["||"] + l)
+                                                       stack[level].pop()
+                                                       stack[level].extend(["||"] + l)
                                                else:
                                                        special_append()
 
index 05c580646651e64c6da8f6d7dc62ef2df3023b57..83735e1fd36ae3ae93f7963716597e8abef79289 100644 (file)
@@ -180,13 +180,13 @@ class UseReduce(TestCase):
                                expected_result = [ "||", [ ["A", "B"], "C"] ]),
                        UseReduceTestCase(
                                "|| ( A || ( B C ) )",
-                               expected_result = [ "||", ["A", "||", ["B", "C"]]]),
+                               expected_result = [ "||", ["A", "B", "C"]]),
                        UseReduceTestCase(
                                "|| ( A || ( B C D ) )",
-                               expected_result = [ "||", ["A", "||", ["B", "C", "D"]] ]),
+                               expected_result = [ "||", ["A", "B", "C", "D"] ]),
                        UseReduceTestCase(
                                "|| ( A || ( B || ( C D ) E ) )",
-                               expected_result = [ "||", ["A", "||", ["B", "||", ["C", "D"], "E"]] ]),
+                               expected_result = [ "||", ["A", "B", "C", "D", "E"] ]),
                        UseReduceTestCase(
                                "( || ( ( ( A ) B ) ) )",
                                expected_result = ["A", "B"] ),
@@ -276,22 +276,22 @@ class UseReduce(TestCase):
                        UseReduceTestCase(
                                "|| ( A B )",
                                opconvert = True,
-                               expected_result = [ ["||", "A", "B"] ]),
+                               expected_result = ["||", "A", "B"]),
                        UseReduceTestCase(
                                "|| ( ( A B ) C )",
                                opconvert = True,
-                               expected_result = [ [ "||", ["A", "B"], "C" ] ]),
+                               expected_result = [ "||", ["A", "B"], "C" ]),
                        UseReduceTestCase(
                                "|| ( A || ( B C ) )",
                                opconvert = True,
-                               expected_result = [ ["||", "A", ["||", "B", "C"]] ]),
+                               expected_result = ["||", "A", "B", "C"]),
                        UseReduceTestCase(
                                "|| ( A || ( B C D ) )",
                                opconvert = True,
-                               expected_result = [ ["||", "A", ["||", "B", "C", "D"]] ]),
+                               expected_result = ["||", "A", "B", "C", "D"]),
                        UseReduceTestCase(
                                "|| ( A || ( B || ( C D ) E ) )",
-                               expected_result = [ "||", ["A", "||", ["B", "||", ["C", "D"], "E"]] ]),
+                               expected_result = [ "||", ["A", "B", "C", "D", "E"] ]),
                        UseReduceTestCase(
                                "( || ( ( ( A ) B ) ) )",
                                opconvert = True,
@@ -348,24 +348,72 @@ class UseReduce(TestCase):
                                opconvert = True,
                                expected_result = ["||", "A", "B"]),
 
-                       # [['||', ['A', 'B'], '||', 'C', 'D']] != ['||', ['A', 'B'], 'C', 'D']
-                       #UseReduceTestCase(
-                       #       "|| ( ( A B ) foo? ( || ( C D ) ) )",
-                       #       uselist = ["foo"],
-                       #       opconvert = True,
-                       #       expected_result = ['||', ['A', 'B'], 'C', 'D']),
-
-                       # ['||', [['A', 'B'], '||', ['C', 'D']]] != ['||', [['A', 'B'], 'C', 'D']]
-                       #UseReduceTestCase(
-                       #       "|| ( ( A B ) foo? ( || ( C D ) ) )",
-                       #       uselist = ["foo"],
-                       #       opconvert = False,
-                       #       expected_result = ['||', [['A', 'B'], 'C', 'D']]),
-
-                       # ['||', [['A', 'B'], '||', ['C', 'D']]] != ['||', [['A', 'B'], 'C', 'D']]
-                       #UseReduceTestCase(
-                       #       "|| ( ( A B ) || ( C D ) )",
-                       #       expected_result = ['||', [['A', 'B'], 'C', 'D']]),
+                       UseReduceTestCase(
+                               "|| ( ( A B ) foo? ( || ( C D ) ) )",
+                               uselist = ["foo"],
+                               opconvert = True,
+                               expected_result = ['||', ['A', 'B'], 'C', 'D']),
+
+                       UseReduceTestCase(
+                               "|| ( ( A B ) foo? ( || ( C D ) ) )",
+                               uselist = ["foo"],
+                               opconvert = False,
+                               expected_result = ['||', [['A', 'B'], 'C', 'D']]),
+
+                       UseReduceTestCase(
+                               "|| ( ( A B ) || ( C D ) )",
+                               expected_result = ['||', [['A', 'B'], 'C', 'D']]),
+
+                       UseReduceTestCase(
+                               "|| ( ( A B ) || ( C D || ( E ( F G ) || ( H ) ) ) )",
+                               expected_result = ['||', [['A', 'B'], 'C', 'D', 'E', ['F', 'G'], 'H']]),
+
+                       UseReduceTestCase(
+                               "|| ( foo? ( A B ) )",
+                               uselist = ["foo"],
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( || ( foo? ( A B ) ) )",
+                               uselist = ["foo"],
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( || ( || ( a? ( b? ( c? ( || ( || ( || ( d? ( e? ( f? ( A B ) ) ) ) ) ) ) ) ) ) ) )",
+                               uselist = ["a", "b", "c", "d", "e", "f"],
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( || ( ( || ( a? ( ( b? ( c? ( || ( || ( || ( ( d? ( e? ( f? ( A B ) ) ) ) ) ) ) ) ) ) ) ) ) ) )",
+                               uselist = ["a", "b", "c", "d", "e", "f"],
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( ( A ( || ( B ) ) ) )",
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( ( A B ) || ( foo? ( bar? ( ( C D || ( baz? ( E ) ( F G ) || ( H ) ) ) ) ) ) )",
+                               uselist = ["foo", "bar", "baz"],
+                               expected_result = ['||', [['A', 'B'], 'C', 'D', '||', ['E', ['F', 'G'], 'H']]]),
+
+                       UseReduceTestCase(
+                               "|| ( foo? ( A B ) )",
+                               uselist = ["foo"],
+                               opconvert=True,
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( || ( foo? ( A B ) ) )",
+                               uselist = ["foo"],
+                               opconvert=True,
+                               expected_result = ['A', 'B']),
+
+                       UseReduceTestCase(
+                               "|| ( || ( || ( a? ( b? ( c? ( || ( || ( || ( d? ( e? ( f? ( A B ) ) ) ) ) ) ) ) ) ) ) )",
+                               uselist = ["a", "b", "c", "d", "e", "f"],
+                               opconvert=True,
+                               expected_result = ['A', 'B']),
 
                        #flat test
                        UseReduceTestCase(