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)
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)
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