def _ensure_all_functions_yield(module):
    """
    All generated functions should contain at least one yield statement.
    This walks the ast to insert a "yield ''" in functions that
    don't otherwise produce output (eg in the case of '<py:def
    function="a"></py:def>')
    """
    functions = {}
    if YieldFrom is not None:
        yield_classes = (Yield, YieldFrom)
    else:
        yield_classes = (Yield,)
    for node, ancestors in astwalk(module):
        if isinstance(node, FunctionDef):
            functions.setdefault(node, False)
        elif isinstance(node, yield_classes):
            f = next(a for a in reversed(ancestors)
                     if isinstance(a, FunctionDef))
            functions[f] = True

    for f in functions:
        if not functions[f]:
            f.body.append(Expr(Yield(Str(s=''))))

    return module
    def compile_call(self, srcnode, parent):
        fn = srcnode.function
        if '(' not in fn:
            fn += '()'
        call = parse_and_strip(fn)[0].value
        leftovers = im.ContainerNode()
        for item in srcnode.children:
            if isinstance(item, im.CallKeyword):
                funcname = self.unique_id(item.name)
                self._compile_function(item, parent, funcname)
                call.keywords.append(keyword(arg=item.name,
                                             value=LoadName(funcname)))
            elif isinstance(item, im.TextNode) and re.match('^\s*$', item.content, re.S):
                continue
            else:
                leftovers.children.append(item)

        if leftovers.children:
            funcname = self.unique_id()
            self._compile_function(leftovers, parent, funcname)
            call.args.append(make_arg(funcname))
        parent.body.append(
            self.annotate_runtime_errors(
                Expr(value=Yield(Call(func=LoadName('str'),
                                      args=[call],
                                      starargs=None,
                                      kwargs=None,
                                      keywords=[]))), srcnode))
    def compile_translationnode(self, srcnode, parent):
        translated = Call(func=LoadName('_'),
                          args=[Str(srcnode.get_msgstr())],
                          starargs=None,
                          kwargs=None,
                          keywords=[])

        named_children = [(name, node)
                          for name, node in srcnode.named_children()
                          if name is not None]

        if not named_children:
            # Simple case - no dynamic children for placeholder replacement
            parent.body.append(Expr(value=Yield(translated)))
            return

        parent.body.append(
            Assign(targets=[StoreName('__piglet_places')],
                    value=Dict([], []))
        )

        for name, node in named_children:
            with self.collect_output(parent) as ACC:
                self._compile(node, parent)
                parent.body.append(
                    Assign(targets=[Subscript(value=LoadName('__piglet_places'),
                                              slice=Index(value=Str(name)),
                                              ctx=Store())],
                           value=Call(func=Attribute(value=Str(s=''), attr='join', ctx=Load()),
                                      args=[LoadName(ACC)],
                                      starargs=None,
                                      kwargs=None,
                                      keywords=[]))
                )

        for name, node in named_children:
            translated = Call(
                func=Attribute(value=translated, attr='replace', ctx=Load()),
                args=[Str('${{{}}}'.format(name)),
                      Subscript(value=LoadName('__piglet_places'),
                                slice=Index(value=Str(name)),
                                ctx=Load())],
                starargs=None,
                kwargs=None,
                keywords=[])
        set_pos(translated, srcnode)
        parent.body.append(Expr(value=Yield(translated)))
Exemple #4
0
    def visit_Yield(self, node):
        existing_node = self.generic_visit(node)
        value = existing_node.value
        if value is None:
            value = Name(id='None', ctx=Load())

        return Yield(value=self._create_bare_context_call(
            'yield_value', [value, Num(n=existing_node.lineno)]))
    def compile_extendsnode(self, srcnode, parent):
        if '$' in srcnode.href:
            value = _interpolated_str_to_ast_value(srcnode.href)
            parent.body.append(Assign(targets=[StoreName('__piglet_tmp')],
                                      value=value))
            loadcode = '__piglet_rt.load(__piglet_template, __piglet_tmp)\n'

        else:
            loadcode = ('__piglet_rt.load(__piglet_template, "{}")\n'
                        .format(srcnode.href))

        parent.body.extend(parse_and_strip(
            '__piglet_parent = {}'
            '__piglet_bases = [__piglet_parent] + __piglet_bases\n'
            .format(loadcode)))

        for n in srcnode.children:
            if isinstance(n, im.BlockNode):
                self.compile_blockreplacenode(n, parent)
            elif isinstance(n, im.DefNode):
                self._compile(n, parent)

        block_ids = [make_block_name(n.name)
                     for n in srcnode.find(im.BlockNode)]

        parent_template_call = Call(
            func=LoadAttribute('__piglet_parent', '__piglet_root__'),
            args=[],
            starargs=None,
            kwargs=None,
            keywords=([keyword(arg='__piglet_bases',
                               value=LoadName('__piglet_bases'))] +
                      [keyword(arg=str(b), value=LoadName(str(b)))
                       for b in block_ids])
        )
        add_kwarg(parent_template_call, '__piglet_extra_blocks')

        if YieldFrom is not None:
            parent.body.append(
                Expr(value=YieldFrom(value=parent_template_call)))
        else:
            loopvar = self.unique_id('loop')
            parent.body.append(
                For(target=Name(id=loopvar, ctx=Store()),
                    iter=parent_template_call,
                    body=[Expr(value=Yield(Name(id=loopvar, ctx=Load())))],
                    orelse=[]))
    def compile_interpolatenode(self, srcnode, parent, mode='yield'):
        value = parse_and_strip(u'x = ({})'.format(srcnode.value))[0].value
        if srcnode.autoescape:
            escaped = Call(func=Name(id='__piglet_escape', ctx=Load()),
                           args=[value],
                           starargs=None,
                           kwargs=None,
                           keywords=[])
        else:
            escaped = Call(func=Name(id='__piglet_ustr', ctx=Load()),
                        args=[value],
                        starargs=None,
                        kwargs=None,
                        keywords=[])

        parent.body.append(self.annotate_runtime_errors(
            Expr(value=Yield(escaped)), srcnode))
    def compile_filternode(self, srcnode, parent):
        func = parse_and_strip(srcnode.function)[0].value

        with self.collect_output(parent) as ACC:
            for node in srcnode.children:
                self._compile(node, parent)

        joined = Call(func=Attribute(value=Str(s=''), attr='join', content=Load()),
                      args=[LoadName(ACC)],
                      starargs=None,
                      kwargs=None,
                      keywords=[])
        parent.body.append(Expr(value=Yield(
            Call(func=func,
                 args=[joined],
                 starargs=None,
                 kwargs=None,
                 keywords=[])
        )))
Exemple #8
0
def parseStatement(parser):
    if parser.matchLexeme(keywords['LET']):
        return parseLetStatement(parser)
    elif parser.matchLexeme(keywords['IF']):
        return parseIfStatement(parser)
    elif parser.matchLexeme(keywords['EACH']):
        return parseEachStatement(parser)
    elif parser.matchLexeme(keywords['ECHO']):
        parser.next()
        if parser.matchTokensort(PRESTRING):
            exp = parseEmbedding(parser)
        else:
            exp = parseExpression(parser)
        parser.check(lexeme=";")
        parser.next()  # skip ;
        return Echo(expression=exp, lineo=parser.currentToken[2])

    elif parser.matchLexeme(keywords['CDATA']):
        parser.next()
        expression = parseExpression(parser)
        return Cdata(expression)
    elif parser.matchLexeme('{'):  #? starts a new staments block
        return parseStatementBlock(parser)
    elif parser.matchLexeme(keywords['COMMENT']):
        parser.next(tokensort=STRING)
        comment = Comment(parser.currentToken[1], lineo=parser.currentToken[2])
        parser.next()
        parser.next()
        return comment
    elif parser.matchLexeme(keywords['YIELD']):
        parser.next(lexeme=";")
        parser.next()
        return Yield()
    elif parser.matchTokensort(NAME):
        markup = parseMarkupStatement(parser)
        return markup
    elif parser.matchTokensort(ENDMARKER):  #needed?
        return
    raise SyntaxError(
        parser.currentToken,
        expected="""statement, "if", "each", "let", "{", "comment",
            "echo", "cdata", "yield" or Markup""")
Exemple #9
0
 def visit_Return(self, node: Return) -> Any:
     value = node.value
     if mask is not None:
         value = BinOp(left=value, op=BitAnd(), right=constant(mask))
     return Expr(value=Yield(value=value))
def yield_value(self, value, srcnode=None):
    expr = Expr(value=Yield(value))
    if srcnode:
        set_pos(expr, srcnode)
    return expr
    def compile_blocknode(self, srcnode, parent, mode='define'):
        """
        Compile a BlockNode (<py:block>).

        :param mode: if 'define' this is a block definition; if 'replace'
                     this is a block being used inside an ExtendsNode to
                     replace the parent template's content.
        """
        assert mode in {'define', 'replace'}

        block_funcname = block_name = make_block_name(srcnode.name)
        block_func = self._compile_function(srcnode,
                                            self.module,
                                            block_funcname,
                                            append=False,
                                            descend=False)
        # A template extending a parent template may override
        # a block without implementing one or more of the nested
        # subblocks from the parent template. The parent will still pass
        # references to the block functions when calling the extending
        # template's block, so we need to be able to accept these.
        add_arg_default(block_func,
                        make_arg('__piglet_bases'),
                        List(elts=[], ctx=Load()))
        block_func.args.kwarg = make_kwarg('__piglet_extra_blocks')
        block_func.body.extend(parse_and_strip('''
            super = __piglet_rt.get_super(__piglet_bases,
                                          __piglet_template,
                                          '{0}')
        '''.format(block_funcname)))

        block_func_call = Call(
            func=LoadName(block_name),
            args=[],
            starargs=None,
            kwargs=None,
            keywords=[keyword(arg='__piglet_bases',
                              value=LoadName('__piglet_bases'))])
        add_kwarg(block_func_call, '__piglet_extra_blocks')

        # Push the current parent context onto the block chain. If nested
        # blocks are encountered, we need to be able to insert default
        # args for inner blocks all the way up the chain. For example::
        #
        #   <py:block name="page">
        #     <py:block name="head">
        #     </py:block>
        #   </py:block>
        #
        # Should generate the function signatures::
        #
        #   def __piglet_head0(...):
        #   def __piglet_page0(..., head=__piglet_head0):
        #   def __piglet_root__(..., page=__piglet_page0, head=__piglet_head0):
        #
        # When compiling the 'head' block, the compiler has to
        # go back and insert the 'head=__piglet_head0' arguments into
        # __piglet_page0 and __piglet_root__. That's what this data structure
        # is for.
        self.block_chain.append((self.get_func(parent), block_func_call))

        # Insert this before existing functions block functions are
        # declared before the containing function. This is required because
        # a reference to the block function is placed in the containing
        # function's argument list
        for ix, n in enumerate(self.module.body):
            if isinstance(n, FunctionDef):
                self.module.body.insert(ix, block_func)
                break
        else:
            self.module.body.append(block_func)

        for item in srcnode.children:
            self._compile(item, block_func)

        # Recursively add this block's function as a keyword argument
        # throughout the caller chain
        for referent, referent_call in self.block_chain:
            add_arg_default(referent,
                            make_arg(block_name),
                            LoadName(block_funcname))
            if referent_call is not block_func_call:
                referent_call.keywords.append(
                    keyword(arg=block_name, value=LoadName(block_name)))

        self.block_chain.pop()

        if mode == 'replace':
            return

        if YieldFrom is not None:
            parent.body.append(Expr(value=YieldFrom(value=block_func_call)))
        else:
            loopitervar = self.unique_id('loop')
            loopvar = self.unique_id('item')

            # Call the block, equivalent to::
            #    for i in BLOCK(**__piglet_extra_blocks):
            #        yield i
            #
            # We pass **__piglet_extra_blocks into BLOCK as it might have
            # subblocks defined that the caller doesn't know about
            parent.body.append(
                Assign(targets=[StoreName(loopitervar)], value=block_func_call)
            )
            loopiter = Name(id=loopitervar, ctx=Load())

            parent.body.append(
                For(target=Name(id=loopvar, ctx=Store()),
                    iter=loopiter,
                    body=[Expr(value=Yield(Name(id=loopvar, ctx=Load())))],
                    orelse=[]))
 def compile_textnode(self, srcnode, parent):
     expr = Expr(value=Yield(Str(srcnode.content)))
     set_pos(expr, srcnode)
     parent.body.append(expr)