def test_duplicate_node_collect(self):
        self.ast_description = """
        file: TestTemplate

        #def test_function
          foo
          bar
          #if True
            #set $foo = 1
          #end if
          baz
          boo
          #if True
            #set $foo = 1
          #end if
        #end def

        NOTE: This test will break if collect_writes is written
        using ast.ASTNode.insert_before.
        """

        ast_root, function_node = self._build_function_template()
        function_node.append(ast.BufferWrite(ast.LiteralNode('foo')))
        function_node.append(ast.BufferWrite(ast.LiteralNode('bar')))
        if_node = ast.IfNode()
        if_node.append(ast.AssignNode(
            ast.IdentifierNode('foo'), ast.LiteralNode(1)))
        function_node.append(if_node)
        function_node.append(ast.BufferWrite(ast.LiteralNode('baz')))
        function_node.append(ast.BufferWrite(ast.LiteralNode('boo')))
        if_node = ast.IfNode()
        if_node.append(ast.AssignNode(
            ast.IdentifierNode('foo'), ast.LiteralNode(1)))
        optimization_analyzer = self._get_analyzer(ast_root)

        ast_root, function_node = self._build_function_template()
        tuple_node = ast.TupleLiteralNode()
        tuple_node.append(ast.LiteralNode('foo'))
        tuple_node.append(ast.LiteralNode('bar'))
        function_node.append(ast.BufferExtend(tuple_node))
        if_node = ast.IfNode()
        if_node.append(ast.AssignNode(
            ast.IdentifierNode('foo'), ast.LiteralNode(1)))
        function_node.append(if_node)
        tuple_node = ast.TupleLiteralNode()
        tuple_node.append(ast.LiteralNode('baz'))
        tuple_node.append(ast.LiteralNode('boo'))
        function_node.append(ast.BufferExtend(tuple_node))
        if_node = ast.IfNode()
        if_node.append(ast.AssignNode(
            ast.IdentifierNode('foo'), ast.LiteralNode(1)))

        expected_hash = hash(ast_root)

        got_hash = hash(optimization_analyzer.optimize_ast())
        self.assertEqual(expected_hash, got_hash)
 def build_conditional_body(node):
     node.append(ast.AssignNode(
         ast.IdentifierNode('_rph_foo'), ast.PlaceholderNode('foo')))
     node.append(ast.AssignNode(
         ast.IdentifierNode('_fph123'), ast.FilterNode(
             ast.IdentifierNode('_rph_foo'))))
     node.append(ast.BufferWrite(ast.IdentifierNode('_fph123')))
    def test_collect_writes_join_if(self):
        self.ast_description = """
        file: TestTemplate

        #def test_function
          foo
          bar
          #if True
            #set $foo = 1
          #end if
          baz
          boo
        #end def
        """

        ast_root, function_node = self._build_function_template()
        function_node.append(ast.BufferWrite(ast.LiteralNode('foo')))
        function_node.append(ast.BufferWrite(ast.LiteralNode('bar')))
        if_node = ast.IfNode()
        if_node.append(ast.AssignNode(
            ast.IdentifierNode('foo'), ast.LiteralNode(1)))
        function_node.append(if_node)
        function_node.append(ast.BufferWrite(ast.LiteralNode('baz')))
        function_node.append(ast.BufferWrite(ast.LiteralNode('boo')))
        optimization_analyzer = self._get_analyzer(ast_root)

        ast_root, function_node = self._build_function_template()
        tuple_node = ast.TupleLiteralNode()
        tuple_node.append(ast.LiteralNode('foo'))
        tuple_node.append(ast.LiteralNode('bar'))
        function_node.append(ast.BufferExtend(tuple_node))
        if_node = ast.IfNode()
        if_node.append(ast.AssignNode(
            ast.IdentifierNode('foo'), ast.LiteralNode(1)))
        function_node.append(if_node)
        tuple_node = ast.TupleLiteralNode()
        tuple_node.append(ast.LiteralNode('baz'))
        tuple_node.append(ast.LiteralNode('boo'))
        function_node.append(ast.BufferExtend(tuple_node))

        expected_hash = hash(ast_root)

        got_hash = hash(optimization_analyzer.optimize_ast())
        self.assertEqual(expected_hash, got_hash)
Beispiel #4
0
    def analyzeTextNode(self, pnode):
        if pnode.child_nodes:
            self.compiler.error(
                SemanticAnalyzerError("ast.TextNode can't have children"),
                pos=pnode.pos)

        value = pnode.value
        if self.options.normalize_whitespace:
            value = text.normalize_whitespace(value)
        literal_node = ast.LiteralNode(value, pos=pnode.pos)
        buffer_write = ast.BufferWrite(literal_node, pos=pnode.pos)
        return [buffer_write]
    def test_collect_writes_join_simple(self):
        self.ast_description = """
        file: TestTemplate

        #def test_function
          foo
          bar
        #end def
        """

        ast_root, function_node = self._build_function_template()
        function_node.append(ast.BufferWrite(ast.LiteralNode('foo')))
        function_node.append(ast.BufferWrite(ast.LiteralNode('bar')))
        optimization_analyzer = self._get_analyzer(ast_root)

        ast_root, function_node = self._build_function_template()
        tuple_node = ast.TupleLiteralNode()
        tuple_node.append(ast.LiteralNode('foo'))
        tuple_node.append(ast.LiteralNode('bar'))
        function_node.append(ast.BufferExtend(tuple_node))
        expected_hash = hash(ast_root)

        got_hash = hash(optimization_analyzer.optimize_ast())
        self.assertEqual(expected_hash, got_hash)
    def test_collect_writes_no_change(self):
        self.ast_description = """
        file: TestTemplate

        #def test_function
          foo
        #end def
        """

        ast_root, function_node = self._build_function_template()
        function_node.append(ast.BufferWrite(ast.LiteralNode('foo')))
        expected_hash = hash(ast_root)

        optimization_analyzer = self._get_analyzer(ast_root)
        got_hash = hash(optimization_analyzer.optimize_ast())
        self.assertEqual(expected_hash, got_hash)
Beispiel #7
0
    def analyzePlaceholderSubstitutionNode(self, pnode):
        # print ' '.join(analyzePlaceholderSubstitutionNode', pnode,
        #                pnode.parameter_list.get_arg_map())
        node_list = []
        ph_expression = self.build_ast(pnode.expression)[0]
        # If the expression contained a macro that was parsed as a
        # fragment, the expression is now a statement and can be moved
        # outside of the ast.PlaceholderSubstitutionNode.
        #
        # This is a hack to get around design decisions that were made
        # early on. It is up to the macro authors to correctly decide how
        # the macro should be parsed and the compiler should throw errors
        # if there is an odd state where nodes are somewhere unexpected.
        if isinstance(ph_expression, ast.statement_nodes):
            return [ph_expression]

        arg_map = pnode.parameter_list.get_arg_map()
        default_format_string = '%s'
        format_string = arg_map.get('format_string', default_format_string)

        skip_filter = False
        cache_forever = False
        registered_function = False
        function_has_only_literal_args = False
        never_cache = False
        if isinstance(ph_expression, ast.CallFunctionNode):
            fname = ph_expression.expression.name
            if self.compiler.registry_contains(fname):
                function_has_only_literal_args = (
                    ph_expression.arg_list and not [
                        _arg for _arg in ph_expression.arg_list
                        if not isinstance(_arg, ast.LiteralNode)
                    ])
                skip_filter = self.compiler.get_registry_value(
                    fname, 'skip_filter')
                skip_unless_baked = self.compiler.get_registry_value(
                    fname, 'skip_filter_unless_baked')
                skip_filter = skip_filter or (not self.template.baked
                                              and skip_unless_baked)
                cache_forever = self.compiler.get_registry_value(
                    fname, 'cache_forever')
                never_cache = self.compiler.get_registry_value(
                    fname, 'never_cache')

            elif ph_expression.library_function:
                # Don't escape function calls into library templates.
                skip_filter = True

        if (self.compiler.enable_filters
                and format_string == default_format_string
                and not isinstance(ph_expression, ast.LiteralNode)):
            arg_node_map = pnode.parameter_list.get_arg_node_map()
            if 'raw' in arg_map:
                # If this is a |raw usage and the template does not allow raw,
                # raise an error.
                self.uses_raw = True
                if (self.options.no_raw
                        and not self.template.explicitly_allow_raw):
                    err_msg = ('|raw is not allowed in templates compiled '
                               'with the --no-raw flag.')
                    self.compiler.error(SemanticAnalyzerError(err_msg),
                                        pos=pnode.pos)
            else:
                # if we need to filter, wrap up the node and wait for further
                # analysis later on
                if skip_filter:
                    # explicitly set the filter to none here - this means we
                    # will cache expensive pseudo-filtered nodes
                    ph_expression = ast.FilterNode(ph_expression,
                                                   None,
                                                   pos=pnode.pos)
                else:
                    ph_expression = ast.FilterNode(
                        ph_expression,
                        arg_node_map.get('filter', ast.DefaultFilterFunction),
                        pos=pnode.pos)

                # if this is a literal node, we still might want to filter it
                # but the output should always be the same - so do it once and
                # cache FIXME: could fold this and apply the function at
                # compile-time
                if (not never_cache and
                    (registered_function and function_has_only_literal_args)
                        or cache_forever or 'cache' in arg_map):
                    cache_expression = ast.CacheNode(ph_expression,
                                                     pos=pnode.pos)
                    self.template.cached_identifiers.add(cache_expression)
                    node_list.append(cache_expression)
                    ph_expression = ast.IdentifierNode(cache_expression.name,
                                                       pos=pnode.pos)

        if isinstance(ph_expression, ast.LiteralNode):
            buffer_write = ast.BufferWrite(ph_expression, pos=pnode.pos)
            node_list.append(buffer_write)
        elif (self.compiler.enable_filters
              and format_string == default_format_string):
            # we are already filtering, don't bother creating a new string
            buffer_write = ast.BufferWrite(ph_expression, pos=pnode.pos)
            node_list.append(buffer_write)
        else:
            buffer_write = ast.BufferWrite(ast.BinOpNode(
                '%', ast.LiteralNode(format_string, pos=pnode.pos),
                ph_expression),
                                           pos=pnode.pos)
            node_list.append(buffer_write)
        return node_list