def _nest_all_elements(tree):
    """
    Manipulate the parse tree by combining all opening and closing html nodes,
    to reflect the nesting of HTML nodes in the tree.
    So where '<p>' and '</p>' where two independent siblings in the source three,
    they become one now, and everything in between is considered a child of this tag.
    """
    # NOTE: this does not yet combile unknown tags, like <fb:like/>,
    #       maybe it's better to replace this code by a more dynamic approach.
    #       Or we can ignore them, like we do know, because we're not unsure
    #       how to thread them.
    def _create_html_tag_node(name):
        class tag_node(HtmlTagPair):
            html_tagname = ''
            def process_params(self, params):
                # Create new node for the opening html tag
                self._open_tag = HtmlTag(name='html-tag')
                self._open_tag.children = params

                # Copy line/column number information
                self._open_tag.line = self.line
                self._open_tag.column = self.column
                self._open_tag.path = self.path

            @property
            def open_tag(self):
                return self._open_tag

            def register_end_node(self, end_node):
                """ Called by 'nest_block_level_elements' for registering the end node """
                self._end_tag = end_node

            def output(self, handler):
                handler(self._open_tag)
                Token.output(self, handler)
                handler(self._end_tag)

        tag_node.__name__ = name
        tag_node.html_tagname = name
        return tag_node

    # Parse all other HTML tags, (useful for validation, it checks whether
    # every opening tag has a closing match. It doesn't hurt, but also doesn't
    # make much sense to enable this in a production environment.)
    block_elements2 = { }

    for t in __ALL_HTML_TAGS:
        block_elements2[(False, HtmlTag, t)] = ((False, HtmlEndTag, t), _create_html_tag_node(t))

    nest_block_level_elements(tree, block_elements2, (HtmlTag, HtmlEndTag),
            lambda c: (c.is_closing_html_tag, c.__class__, c.html_tagname) )
def _nest_all_elements(tree):
    """
    Manipulate the parse tree by combining all opening and closing html nodes,
    to reflect the nesting of HTML nodes in the tree.
    """

    def _create_html_tag_node(name):
        class tag_node(HtmlNode):
            html_tagname = ""

            def process_params(self, params):
                self.__open_tag = HtmlTag()
                self.__open_tag.children = params

            @property
            def open_tag(self):
                return self.__open_tag

            def output(self, handler):
                self.__open_tag.output(handler)
                Token.output(self, handler)
                handler("</%s>" % name)

        tag_node.__name__ = name
        tag_node.html_tagname = name
        return tag_node

    # Parse all other HTML tags, (useful for validation, it checks whether
    # every opening tag has a closing match. It doesn't hurt, but also doesn't
    # make much sense to enable this in a production environment.)
    block_elements2 = {}

    for t in __ALL_HTML_TAGS:
        block_elements2[(False, HtmlTag, t)] = ((False, HtmlEndTag, t), _create_html_tag_node(t))

    nest_block_level_elements(
        tree, block_elements2, [HtmlTag, HtmlEndTag], lambda c: (c.is_closing_html_tag, c.__class__, c.html_tagname)
    )
def _nest_elements(tree):
    """
    Example:
    Replace (<script>, content, </script>) nodes by a single node, moving the
    child nodes to the script's content.
    """
    block_elements1 = {"html-start-conditional-comment": ("html-end-conditional-comment", HtmlConditionalComment)}
    nest_block_level_elements(tree, block_elements1, [Token], lambda c: c.name)

    # Read as: move the content between:
    # element of this class, with this html_tagname, and
    # element of the other class, with the other html_tagname,
    # to a new parse node of the latter class.
    block_elements2 = {
        (False, HtmlTag, "script"): ((False, HtmlEndTag, "script"), HtmlScriptNode),
        (False, HtmlTag, "style"): ((False, HtmlEndTag, "style"), HtmlStyleNode),
        (False, HtmlTag, "pre"): ((False, HtmlEndTag, "pre"), HtmlPreNode),
        (False, HtmlTag, "textarea"): ((False, HtmlEndTag, "textarea"), HtmlTextareaNode),
    }

    nest_block_level_elements(
        tree, block_elements2, [HtmlTag, HtmlEndTag], lambda c: (c.is_closing_html_tag, c.__class__, c.html_tagname)
    )
def parse(source_code, path, context, main_template=False):
    """
    Parse the code.
    - source_code: string
    - path: for attaching meta information to the tree.
    - context: preprocess context (holding the settings/dependecies/warnings, ...)
    - main_template: False for includes/extended templates. True for the
                     original path that was called.
    """
    # To start, create the root node of a tree.
    tree = Token(name="root", line=1, column=1, path=path)
    tree.children = [source_code]

    # Lex Django tags
    tokenize(tree, __DJANGO_STATES, Token)

    # Phase I: add parser extensions
    _add_parser_extensions(tree)

    # Phase II: process inline tags
    _process_inline_tags(tree)

    # Phase III: create recursive structure for block level tags.
    nest_block_level_elements(tree, __DJANGO_BLOCK_ELEMENTS, DjangoTag, lambda c: c.tagname)

    # === Actions ===

    if main_template:
        _find_first_level_dependencies(tree, context)

    # Extend parent template and process includes
    tree = _process_extends(tree, context)  # NOTE: this returns a new tree!
    _preprocess_includes(tree, context)
    _preprocess_decorate_tags(tree, context)

    # Following actions only need to be applied if this is the 'main' tree.
    # It does not make sense to apply it on every include, and then again
    # on the complete tree.
    if main_template:

        _update_preprocess_settings(tree, context)
        options = context.options

        # Remember translations in context (form PO-file generation)
        remember_gettext_entries(tree, context)

        # Do translations
        if options.preprocess_translations:
            _preprocess_trans_tags(tree)

        # Reverse URLS
        if options.preprocess_urls:
            _preprocess_urls(tree)

        # Do variable lookups
        if options.preprocess_variables:
            sites_enabled = "django.contrib.sites" in settings.INSTALLED_APPS

            _preprocess_variables(
                tree,
                {"MEDIA_URL": getattr(settings, "MEDIA_URL", ""), "STATIC_URL": getattr(settings, "STATIC_URL", "")},
            )
            if sites_enabled:
                from django.contrib.sites.models import Site

                try:
                    # Don't preprocess anything when we don't have a Site
                    # instance yet.
                    site = Site.objects.get_current()
                    _preprocess_variables(
                        tree,
                        {"SITE_DOMAIN": site.domain, "SITE_NAME": site.name, "SITE_URL": "http://%s" % site.domain},
                    )
                except Site.DoesNotExist, e:
                    pass

        # Don't output {% block %} tags in the compiled file.
        if options.remove_block_tags:
            tree.collapse_nodes_of_class(DjangoBlockTag)

        # Preprocess {% callmacro %} tags
        if options.preprocess_macros:
            _preprocess_macros(tree)

        # Group all {% load %} statements
        if options.merge_all_load_tags:
            _group_all_loads(tree)

        # Preprocessable tags
        if options.execute_preprocessable_tags:
            _execute_preprocessable_tags(tree)

        # HTML compiler
        if options.is_html:
            compile_html(tree, context)
def parse(source_code, path, context, main_template=False):
    """
    Parse the code.
    - source_code: string
    - path: for attaching meta information to the tree.
    - context: preprocess context (holding the settings/dependecies/warnings, ...)
    - main_template: False for includes/extended templates. True for the
                     original path that was called.
    """
    # To start, create the root node of a tree.
    tree = Token(name='root', line=1, column=1, path=path)
    tree.children = [ source_code ]

    # Lex Django tags
    tokenize(tree, __DJANGO_STATES, Token)

    # Phase I: add parser extensions
    _add_parser_extensions(tree)

    # Phase II: process inline tags
    _process_inline_tags(tree)

    # Phase III: create recursive structure for block level tags.
    nest_block_level_elements(tree, __DJANGO_BLOCK_ELEMENTS, DjangoTag, lambda c: c.tagname)

    # === Actions ===

    if main_template:
        _find_first_level_dependencies(tree, context)

    # Extend parent template and process includes
    tree = _process_extends(tree, context) # NOTE: this returns a new tree!
    _preprocess_includes(tree, context)
    _preprocess_decorate_tags(tree, context)

    # Following actions only need to be applied if this is the 'main' tree.
    # It does not make sense to apply it on every include, and then again
    # on the complete tree.
    if main_template:

        _update_preprocess_settings(tree, context)
        options = context.options

        # Remember translations in context (form PO-file generation)
        remember_gettext_entries(tree, context)

        # Do translations
        if options.preprocess_translations:
            _preprocess_trans_tags(tree)

        # Reverse URLS
        if options.preprocess_urls:
            _preprocess_urls(tree)

        # Do variable lookups
        if options.preprocess_variables:
            sites_enabled = 'django.contrib.sites' in settings.INSTALLED_APPS

            _preprocess_variables(tree,
                        {
                            'MEDIA_URL': getattr(settings, 'MEDIA_URL', ''),
                            'STATIC_URL': getattr(settings, 'STATIC_URL', ''),
                        })
            if sites_enabled:
                from django.contrib.sites.models import Site
                try:
                    # Don't preprocess anything when we don't have a Site
                    # instance yet.
                    site = Site.objects.get_current()
                    _preprocess_variables(tree,
                            {
                                'SITE_DOMAIN': site.domain,
                                'SITE_NAME': site.name,
                                'SITE_URL': 'http://%s' % site.domain,
                            })
                except Site.DoesNotExist, e:
                    pass

        # Don't output {% block %} tags in the compiled file.
        if options.remove_block_tags:
            tree.collapse_nodes_of_class(DjangoBlockTag)

        # Preprocess {% callmacro %} tags
        if options.preprocess_macros:
            _preprocess_macros(tree)

        # Group all {% load %} statements
        if options.merge_all_load_tags:
            _group_all_loads(tree)

        # Preprocessable tags
        if options.execute_preprocessable_tags:
            _execute_preprocessable_tags(tree)

        # HTML compiler
        if options.is_html:
            compile_html(tree, context)
def parse(source_code, path, loader, main_template=False, options=None):
    """
    Parse the code.
    - source_code: string
    - loader: method to be called to include other templates.
    - path: for attaching meta information to the tree.
    - main_template: False for includes/extended templates. True for the
                     original path that was called.
    """
    # To start, create the root node of a tree.
    tree = Token(name='root', line=1, column=1, path=path)
    tree.children = [ source_code ]

    # Lex Django tags
    tokenize(tree, __DJANGO_STATES, [Token])

    # Phase I: add parser extensions
    _add_parser_extensions(tree)

    # Phase II: process inline tags
    _process_inline_tags(tree)

    # Phase III: create recursive structure for block level tags.
    nest_block_level_elements(tree, __DJANGO_BLOCK_ELEMENTS, [DjangoTag], lambda c: c.tagname)

    # === Actions ===

    # Extend parent template and process includes
    tree = _process_extends(tree, loader) # NOTE: this returns a new tree!
    _preprocess_includes(tree, loader)
    _preprocess_decorate_tags(tree, loader)


    # Following actions only need to be applied if this is the 'main' tree.
    # It does not make sense to apply it on every include, and then again
    # on the complete tree.
    if main_template:
        options = _get_preprocess_settings(tree, options)

        # Do translations
        if options.preprocess_translations:
            _preprocess_trans_tags(tree)

        # Reverse URLS
        if options.preprocess_urls:
            _preprocess_urls(tree)

        # Do variable lookups
        if options.preprocess_variables:
            from django.contrib.sites.models import Site
            _preprocess_variables(tree,
                        {
                            'MEDIA_URL': settings.MEDIA_URL,
                            'SITE_DOMAIN': Site.objects.get_current().domain,
                            'SITE_NAME': Site.objects.get_current().name,
                            'SITE_URL': 'http://%s' % Site.objects.get_current().domain,
                        })

        # Don't output {% block %} tags in the compiled file.
        if options.remove_block_tags:
            tree.collapse_nodes_of_class(DjangoBlockTag)

        # Preprocess {% callmacro %} tags
        if options.preprocess_macros:
            _preprocess_macros(tree)

        if options.preprocess_ifdebug:
            _preprocess_ifdebug(tree)

        # Group all {% load %} statements
        if options.merge_all_load_tags:
            _group_all_loads(tree)

        # Preprocessable tags
        if options.execute_preprocessable_tags:
            _execute_preprocessable_tags(tree)

        # HTML compiler
        if options.is_html:
            compile_html(tree, options)

    return tree