.. only:: html

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

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

    .. _sphx_glr_examples_advanced_prioritizer.py:


Custom SPPF Prioritizer
=======================

This example demonstrates how to subclass ``ForestVisitor`` to make a custom
SPPF node prioritizer to be used in conjunction with ``TreeForestTransformer``.

Our prioritizer will count the number of descendants of a node that are tokens.
By negating this count, our prioritizer will prefer nodes with fewer token
descendants. Thus, we choose the more specific parse.


.. code-block:: default


    from lark import Lark
    from lark.parsers.earley_forest import ForestVisitor, TreeForestTransformer

    class TokenPrioritizer(ForestVisitor):

        def visit_symbol_node_in(self, node):
            # visit the entire forest by returning node.children
            return node.children

        def visit_packed_node_in(self, node):
            return node.children

        def visit_symbol_node_out(self, node):
            priority = 0
            for child in node.children:
                # Tokens do not have a priority attribute
                # count them as -1
                priority += getattr(child, 'priority', -1)
            node.priority = priority

        def visit_packed_node_out(self, node):
            priority = 0
            for child in node.children:
                priority += getattr(child, 'priority', -1)
            node.priority = priority

        def on_cycle(self, node, path):
            raise Exception("Oops, we encountered a cycle.")

    grammar = """
    start: hello " " world | hello_world
    hello: "Hello"
    world: "World"
    hello_world: "Hello World"
    """

    parser = Lark(grammar, parser='earley', ambiguity='forest')
    forest = parser.parse("Hello World")

    print("Default prioritizer:")
    tree = TreeForestTransformer(resolve_ambiguity=True).transform(forest)
    print(tree.pretty())

    forest = parser.parse("Hello World")

    print("Custom prioritizer:")
    tree = TreeForestTransformer(resolve_ambiguity=True, prioritizer=TokenPrioritizer()).transform(forest)
    print(tree.pretty())

    # Output:
    #
    # Default prioritizer:
    # start
    #   hello Hello
    #
    #   world World
    #
    # Custom prioritizer:
    # start
    #   hello_world   Hello World


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

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


.. _sphx_glr_download_examples_advanced_prioritizer.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: prioritizer.py <prioritizer.py>`



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

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


.. only:: html

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

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