.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        Click :ref:`here <sphx_glr_download_examples_advanced_python_bytecode.py>`     to download the full example code
    .. rst-class:: sphx-glr-example-title

    .. _sphx_glr_examples_advanced_python_bytecode.py:


Compile Python to Bytecode
==========================
 
A toy example that compiles Python directly to bytecode, without generating an AST.
It currently only works for very very simple Python code.

It requires the 'bytecode' library. You can get it using
::

    $ pip install bytecode


.. code-block:: default

    from lark import Lark, Transformer, v_args
    from lark.indenter import Indenter

    from bytecode import Instr, Bytecode

    class PythonIndenter(Indenter):
        NL_type = '_NEWLINE'
        OPEN_PAREN_types = ['LPAR', 'LSQB', 'LBRACE']
        CLOSE_PAREN_types = ['RPAR', 'RSQB', 'RBRACE']
        INDENT_type = '_INDENT'
        DEDENT_type = '_DEDENT'
        tab_len = 8


    @v_args(inline=True)
    class Compile(Transformer):
        def number(self, n):
            return [Instr('LOAD_CONST', int(n))]
        def string(self, s):
            return [Instr('LOAD_CONST', s[1:-1])]
        def var(self, n):
            return [Instr('LOAD_NAME', n)]

        def arith_expr(self, a, op, b):
            # TODO support chain arithmetic
            assert op == '+'
            return a + b + [Instr('BINARY_ADD')]

        def arguments(self, args):
            return args

        def funccall(self, name, args):
            return name + args + [Instr('CALL_FUNCTION', 1)]

        @v_args(inline=False)
        def file_input(self, stmts):
            return sum(stmts, []) + [Instr("RETURN_VALUE")]

        def expr_stmt(self, lval, rval):
            # TODO more complicated than that
            name ,= lval
            assert name.name == 'LOAD_NAME' # XXX avoid with another layer of abstraction
            return rval + [Instr("STORE_NAME", name.arg)]

        def __default__(self, *args):
            assert False, args


    python_parser3 = Lark.open('python3.lark', rel_to=__file__, start='file_input',
                               parser='lalr', postlex=PythonIndenter(),
                               transformer=Compile(), propagate_positions=False)

    def compile_python(s):
        insts = python_parser3.parse(s+"\n")
        return Bytecode(insts).to_code()

    code = compile_python("""
    a = 3
    b = 5
    print("Hello World!")
    print(a+(b+2))
    print((a+b)+2)
    """)
    exec(code)
    # -- Output --
    # Hello World!
    # 10
    # 10


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** ( 0 minutes  0.000 seconds)


.. _sphx_glr_download_examples_advanced_python_bytecode.py:


.. only :: html

 .. container:: sphx-glr-footer
    :class: sphx-glr-footer-example



  .. container:: sphx-glr-download sphx-glr-download-python

     :download:`Download Python source code: python_bytecode.py <python_bytecode.py>`



  .. container:: sphx-glr-download sphx-glr-download-jupyter

     :download:`Download Jupyter notebook: python_bytecode.ipynb <python_bytecode.ipynb>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
