Python FizzBuzz with AST

An attempt to solve FizzBuzz with 100 print() statement—with extra steps.

Inspiration came from the first chapter in this book. Do it with Python’s abstract syntax tree.

This function creates an ast.Module to which all print statements are appended. These statements are created and extracted on the first couple of lines.

The print-statements are appended in the most trivial way possible with if/elif/else block.

import copy
import ast

fizz = ast.parse("print('fizz')").body[0]
buzz = ast.parse("print('buzz')").body[0]
fizzbuzz = ast.parse("print('fizzbuzz')").body[0]
# Three alone is an expression; not _ast.Constant
constant = ast.parse('3').body[0].value
ast_print = ast.parse('print()').body[0]


def create_ast():
    print_stmt = copy.deepcopy(ast_print)
    print_stmt.value.args.append(None)
    cur_const = copy.deepcopy(constant)

    i = ast.Module()
    i.type_ignores = []
    i.body = []
    for j in range(100):
        if not j % 15:
            i.body.append(fizzbuzz)
        elif not j % 3:
            i.body.append(fizz)
        elif not j % 5:
            i.body.append(buzz)
        else:
            cur_const.value = j
            print_stmt.value.args[0] = cur_const
            # Create a deep-copy, otherwise it's all by reference
            i.body.append(copy.deepcopy(print_stmt))
    ast.fix_missing_locations(i)
    return i


if __name__ == '__main__':
    exec(compile(create_ast(), filename="<ast>", mode="exec"))

References

https://greentreesnakes.readthedocs.io/

Open Questions

  • Is it possible to have self-modifying code in Python?
    • The AST isn’t growing but looping and modifying itself.