DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (e2394b695d21)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
import WebIDL
import itertools
import string

# We'd like to use itertools.chain but it's 2.6 or higher.
def chain(*iterables):
    # chain('ABC', 'DEF') --> A B C D E F
    for it in iterables:
        for element in it:
            yield element

# We'd like to use itertools.combinations but it's 2.6 or higher.
def combinations(iterable, r):
    # combinations('ABCD', 2) --> AB AC AD BC BD CD
    # combinations(range(4), 3) --> 012 013 023 123
    pool = tuple(iterable)
    n = len(pool)
    if r > n:
        return
    indices = list(range(r))
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != i + n - r:
                break
        else:
            return
        indices[i] += 1
        for j in range(i+1, r):
            indices[j] = indices[j-1] + 1
        yield tuple(pool[i] for i in indices)

# We'd like to use itertools.combinations_with_replacement but it's 2.7 or
# higher.
def combinations_with_replacement(iterable, r):
    # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
    pool = tuple(iterable)
    n = len(pool)
    if not n and r:
        return
    indices = [0] * r
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != n - 1:
                break
        else:
            return
        indices[i:] = [indices[i] + 1] * (r - i)
        yield tuple(pool[i] for i in indices)

def WebIDLTest(parser, harness):
    types = ["float",
             "double",
             "short",
             "unsigned short",
             "long",
             "unsigned long",
             "long long",
             "unsigned long long",
             "boolean",
             "byte",
             "octet",
             "DOMString",
             "ByteString",
             "USVString",
             #"sequence<float>",
             "object",
             "ArrayBuffer",
             #"Date",
             "TestInterface1",
             "TestInterface2"]

    testPre = """
        interface TestInterface1 {
        };
        interface TestInterface2 {
        };
        """

    interface = testPre + """
        interface PrepareForTest {
        """
    for (i, type) in enumerate(types):
        interface += string.Template("""
          readonly attribute ${type} attr${i};
        """).substitute(i=i, type=type)
    interface += """
        };
        """

    parser.parse(interface)
    results = parser.finish()

    iface = results[2]

    parser = parser.reset()

    def typesAreDistinguishable(t):
        return all(u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2))
    def typesAreNotDistinguishable(t):
        return any(not u[0].isDistinguishableFrom(u[1]) for u in combinations(t, 2))
    def unionTypeName(t):
        if len(t) > 2:
            t[0:2] = [unionTypeName(t[0:2])]
        return "(" + " or ".join(t) + ")"

    # typeCombinations is an iterable of tuples containing the name of the type
    # as a string and the parsed IDL type.
    def unionTypes(typeCombinations, predicate):
        for c in typeCombinations:
            if predicate(t[1] for t in c):
                yield unionTypeName([t[0] for t in c])

    # We limit invalid union types with a union member type to the subset of 3
    # types with one invalid combination.
    # typeCombinations is an iterable of tuples containing the name of the type
    # as a string and the parsed IDL type.
    def invalidUnionWithUnion(typeCombinations):
        for c in typeCombinations:
            if (typesAreNotDistinguishable((c[0][1], c[1][1])) and
                typesAreDistinguishable((c[1][1], c[2][1])) and
                typesAreDistinguishable((c[0][1], c[2][1]))):
                yield unionTypeName([t[0] for t in c])

    # Create a list of tuples containing the name of the type as a string and
    # the parsed IDL type.
    types = zip(types, (a.type for a in iface.members))

    validUnionTypes = chain(unionTypes(combinations(types, 2), typesAreDistinguishable),
                            unionTypes(combinations(types, 3), typesAreDistinguishable))
    invalidUnionTypes = chain(unionTypes(combinations_with_replacement(types, 2), typesAreNotDistinguishable),
                              invalidUnionWithUnion(combinations(types, 3)))
    interface = testPre + """
        interface TestUnion {
        """
    for (i, type) in enumerate(validUnionTypes):
        interface += string.Template("""
          void method${i}(${type} arg);
          ${type} returnMethod${i}();
          attribute ${type} attr${i};
          void optionalMethod${i}(${type}? arg);
        """).substitute(i=i, type=type)
    interface += """
        };
        """
    parser.parse(interface)
    results = parser.finish()

    parser = parser.reset()

    for invalid in invalidUnionTypes:
        interface = testPre + string.Template("""
            interface TestUnion {
              void method(${type} arg);
            };
        """).substitute(type=invalid)

        threw = False
        try:
            parser.parse(interface)
            results = parser.finish()
        except:
            threw = True

        harness.ok(threw, "Should have thrown.")

        parser = parser.reset()