| 137 | self.resetTokenClass() |
| 138 | |
| 139 | def bound_collection_from_tokens(self, tokens, t, i, collection_type): |
| 140 | count = t.attr |
| 141 | assert isinstance(count, int) |
| 142 | |
| 143 | assert count <= i |
| 144 | |
| 145 | if collection_type == "CONST_DICT": |
| 146 | # constant dictionaries work via BUILD_CONST_KEY_MAP and |
| 147 | # handle the values() like sets and lists. |
| 148 | # However, the keys() are an LOAD_CONST of the keys. |
| 149 | # adjust offset to account for this |
| 150 | count += 1 |
| 151 | |
| 152 | # For small lists don't bother |
| 153 | if count < 5: |
| 154 | return None |
| 155 | |
| 156 | collection_start = i - count |
| 157 | |
| 158 | for j in range(collection_start, i): |
| 159 | if tokens[j].kind not in ( |
| 160 | "LOAD_CONST", |
| 161 | "LOAD_FAST", |
| 162 | "LOAD_GLOBAL", |
| 163 | "LOAD_NAME", |
| 164 | ): |
| 165 | return None |
| 166 | |
| 167 | collection_enum = CONST_COLLECTIONS.index(collection_type) |
| 168 | |
| 169 | # If we go there all instructions before tokens[i] are LOAD_CONST and we can replace |
| 170 | # add a boundary marker and change LOAD_CONST to something else |
| 171 | new_tokens = tokens[:-count] |
| 172 | start_offset = tokens[collection_start].offset |
| 173 | new_tokens.append( |
| 174 | Token( |
| 175 | opname="COLLECTION_START", |
| 176 | attr=collection_enum, |
| 177 | pattr=collection_type, |
| 178 | offset="%s_0" % start_offset, |
| 179 | has_arg=True, |
| 180 | opc=self.opc, |
| 181 | has_extended_arg=False, |
| 182 | ) |
| 183 | ) |
| 184 | for j in range(collection_start, i): |
| 185 | if tokens[j] == "LOAD_CONST": |
| 186 | opname = "ADD_VALUE" |
| 187 | else: |
| 188 | opname = "ADD_VALUE_VAR" |
| 189 | new_tokens.append( |
| 190 | Token( |
| 191 | opname=opname, |
| 192 | attr=tokens[j].attr, |
| 193 | pattr=tokens[j].pattr, |
| 194 | offset=tokens[j].offset, |
| 195 | has_arg=True, |
| 196 | linestart=tokens[j].linestart, |