HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Python preprocesser that allows "until" and "unless" statements

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
allowsunlessuntilpreprocesserstatementsthatpythonand

Problem

I've implemented the beginnings of a Python preprocesser I plan to implement sometime in the future, and the below code is my simple prototype. At the moment, it only converts until and unless statements.

py_preproc.py

"""
A simple Python utility that converts
non-valid Python code, like `until`,
and `unless` blocks to valid Python 
code.
"""
from sys import argv

try:
    file_path = argv[1]
    execute_results = argv[2]
except IndexError:
    raise Exception("Two argv arguments are required, file_path, and execute_results.")

def open_code_file():
    """
    Opens the code file to do the conversion
    on, and returns the read version as a
    string.
    """
    with open(file_path, "r+") as code_file:
        return code_file.read()

def replace_items(file_string):
    """
    Replace specific pieces of the code_file
    with valid Python code. Currently only
    `until`, and `unless` blocks are replaced.
    """
    return file_string.replace(
        "until", "while not"
    ).replace(
        "unless", "if not"
    )

def evaluate_result(result_string):
    """
    Evaluates the converted result, after
    the code has been converted to valid
    Python code.
    """
    py_string_compiled = compile(result_string, "fakemodule", "exec")
    exec(py_string_compiled)

def main():
    file_string = open_code_file()
    new_file_string = replace_items(file_string)

    if execute_results == "-true":
        evaluate_result(new_file_string)

    elif execute_results == "-false":
        with open(file_path) as file_to_write:
            file_to_write.truncate()
            file_to_write.write(new_file_string)

    else:
        raise Exception("Invalid argument \"{argument}\".".format(argument=execute_results))

if __name__ == '__main__':
    main()


For reference, here's an example of a code file using until and unless, before it's preprocessed.

```
iterator = 10

until iterator == 0:
print(iterator)
iterator -= 1

unless iterator != 0:

Solution

-
Remco Gerlich is quite right to point out that this preprocessor does not work on general Python code, because it uses string replacement. Thus unless will be changed to if not in strings (such as regular expressions, templates, and docstrings), potentially breaking the code. The preprocessor itself is just one example of the kind of code which will be broken: it is not good enough to respond that this concern is "silly".

-
Additionally, Bakuriu is quite right to point out that the transformation of unless to if not is inadequate: it only works on very simple examples. But consider:

a unless b or c else d


which would be changed to:

a if not b or c else d


where the condition is wrong, because not b or c parses as (not b) or c. The correct transformation is:

a if not (b or c) else d


This problem makes it hopeless to attempt this preprocessing at the level of text, or even of tokens: you need a parser to find the end of the condition. Consider an expression like:

a unless b or (c unless d and e else f) else g


which needs to be transformed into:

a if not (b or (c if not (d and e) else f)) else g

Code Snippets

a unless b or c else d
a if not b or c else d
a if not (b or c) else d
a unless b or (c unless d and e else f) else g
a if not (b or (c if not (d and e) else f)) else g

Context

StackExchange Code Review Q#95055, answer score: 14

Revisions (0)

No revisions yet.