Source code for ideas.examples.switch
"""switch.py
-----------------
Implements something similar to version 1.B of
`PEP 3103 <https://www.python.org/dev/peps/pep-3103>`_
"""
from ideas import import_hook, utils
import token_utils
[docs]def transform_source(source, callback_params=None, **_kwargs):
"""Replaces code like::
switch EXPR:
case EXPR_1:
SUITE
case EXPR_2:
SUITE
case in EXPR_3, EXPR_4, ...:
SUITE
...
else:
SUITE
by::
var_name = EXPR
if var_name == EXPR_1:
SUITE
elif var_name == EXPR_2:
SUITE
elif var_name in EXPR_3, EXPR_4, ...:
SUITE
else:
SUITE
del var_name
Limitation: switch blocks cannot be part of a SUITE of another switch block.
"""
if callback_params is None or "predictable_names" not in callback_params:
predictable_names = False
else:
predictable_names = callback_params["predictable_names"]
new_tokens = []
switch_block = False
first_case = False
if predictable_names:
variable_name = utils.generate_predictable_names()
else:
variable_name = utils.generate_variable_names()
for line in token_utils.get_lines(source):
first_token = token_utils.get_first(line)
if first_token is None:
new_tokens.extend(line)
continue
if len(line) > 1:
_index = token_utils.get_first_index(line)
second_token = line[_index + 1]
else:
second_token = None
if not switch_block:
if first_token == "switch":
switch_indent = first_token.start_col
var_name = next(variable_name)
first_token.string = f"{var_name} ="
switch_block = True
first_case = True
colon = token_utils.get_last(line)
colon.string = ""
else:
if first_token.start_col == switch_indent:
switch_block = False
new_tokens.extend([" " * switch_indent + f"del {var_name}\n"])
elif first_token == "case" or first_token == "else":
if first_case and first_token == "case":
if second_token == "in":
first_token.string = f"if {var_name}"
else:
first_token.string = f"if {var_name} =="
first_case = False
elif first_token == "case":
if second_token == "in":
first_token.string = f"elif {var_name}"
else:
first_token.string = f"elif {var_name} =="
dedent = first_token.start_col - switch_indent
line = token_utils.dedent(line, dedent)
new_tokens.extend(line)
return token_utils.untokenize(new_tokens)
[docs]def add_hook(
predictable_names=False,
**_kwargs,
):
"""Creates and adds the import hook in sys.meta_path"""
callback_params = {"predictable_names": predictable_names}
hook = import_hook.create_hook(
transform_source=transform_source,
callback_params=callback_params,
hook_name=__name__,
)
return hook