Start handling BUILD_MAP (a class of dict)

This commit is contained in:
rocky
2022-04-26 15:37:42 -04:00
parent 81ff994a41
commit c25fa61e33
5 changed files with 135 additions and 3 deletions

View File

@@ -210,6 +210,10 @@ class Scanner3(Scanner):
def bound_collection_from_inst(
self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int, collection_type: str
) -> Optional[list]:
"""
Try to a sequence of instruction that ends with a BUILD_xxx into a sequence that can
be parsed much faster, but inserting the token boundary at the beginning of the sequence.
"""
count = t.attr
assert isinstance(count, int)
@@ -285,6 +289,94 @@ class Scanner3(Scanner):
)
return new_tokens
def bound_map_from_inst(
self, insts: list, next_tokens: list, inst: Instruction, t: Token, i: int) -> Optional[list]:
"""
Try to a sequence of instruction that ends with a BUILD_MAP into a sequence that can
be parsed much faster, but inserting the token boundary at the beginning of the sequence.
"""
count = t.attr
assert isinstance(count, int)
if count > i:
return None
# For small lists don't bother
if count < 5:
return None
collection_start = i - (count * 2)
assert (count * 2) <= i
for j in range(collection_start, i, 2):
if insts[j].opname not in (
"LOAD_CONST",
):
return None
if insts[j+1].opname not in (
"LOAD_CONST",
):
return None
collection_start = i - (2 * count)
collection_enum = CONST_COLLECTIONS.index("CONST_MAP")
# If we get here, all instructions before tokens[i] are LOAD_CONST and we can replace
# add a boundary marker and change LOAD_CONST to something else
new_tokens = next_tokens[:-(2*count)]
start_offset = insts[collection_start].offset
new_tokens.append(
Token(
opname="COLLECTION_START",
attr=collection_enum,
pattr="CONST_MAP",
offset=f"{start_offset}_0",
linestart=False,
has_arg=True,
has_extended_arg=False,
opc=self.opc,
)
)
for j in range(collection_start, i, 2):
new_tokens.append(
Token(
opname="ADD_KEY",
attr=insts[j].argval,
pattr=insts[j].argrepr,
offset=insts[j].offset,
linestart=insts[j].starts_line,
has_arg=True,
has_extended_arg=False,
opc=self.opc,
)
)
new_tokens.append(
Token(
opname="ADD_VALUE",
attr=insts[j+1].argval,
pattr=insts[j+1].argrepr,
offset=insts[j+1].offset,
linestart=insts[j+1].starts_line,
has_arg=True,
has_extended_arg=False,
opc=self.opc,
)
)
new_tokens.append(
Token(
opname=f"BUILD_DICT_OLDER",
attr=t.attr,
pattr=t.pattr,
offset=t.offset,
linestart=t.linestart,
has_arg=t.has_arg,
has_extended_arg=False,
opc=t.opc,
)
)
return new_tokens
def ingest(self, co, classname=None, code_objects={}, show_asm=None
) -> Tuple[list, dict]:
"""
@@ -411,6 +503,15 @@ class Scanner3(Scanner):
if try_tokens is not None:
new_tokens = try_tokens
continue
elif opname in (
"BUILD_MAP",
):
try_tokens = self.bound_map_from_inst(
self.insts, new_tokens, inst, t, i,
)
if try_tokens is not None:
new_tokens = try_tokens
continue
argval = inst.argval
op = inst.opcode