Exemple #1
0
 def parse_dict(self):
     token = self.stream.expect('lbrace')
     items = []
     while self.stream.current.type != 'rbrace':
         if items:
             self.stream.expect('comma')
         if self.stream.current.type == 'rbrace':
             break
         key = self.parse_expression()
         self.stream.expect('colon')
         value = self.parse_expression()
         items.append(nodes.Pair(key, value, lineno=key.lineno))
     self.stream.expect('rbrace')
     return nodes.Dict(items, lineno=token.lineno)
Exemple #2
0
    def _make_node(self, singular, plural, variables, plural_expr,
                   vars_referenced, num_called_num):
        """Generates a useful node from the data provided."""
        # no variables referenced?  no need to escape for old style
        # gettext invocations only if there are vars.
        if not vars_referenced and not self.environment.newstyle_gettext:
            singular = singular.replace('%%', '%')
            if plural:
                plural = plural.replace('%%', '%')

        # singular only:
        if plural_expr is None:
            gettext = nodes.Name('gettext', 'load')
            node = nodes.Call(gettext, [nodes.Const(singular)],
                              [], None, None)

        # singular and plural
        else:
            ngettext = nodes.Name('ngettext', 'load')
            node = nodes.Call(ngettext, [
                nodes.Const(singular),
                nodes.Const(plural),
                plural_expr
            ], [], None, None)

        # in case newstyle gettext is used, the method is powerful
        # enough to handle the variable expansion and autoescape
        # handling itself
        if self.environment.newstyle_gettext:
            for key, value in iteritems(variables):
                # the function adds that later anyways in case num was
                # called num, so just skip it.
                if num_called_num and key == 'num':
                    continue
                node.kwargs.append(nodes.Keyword(key, value))

        # otherwise do that here
        else:
            # mark the return value as safe if we are in an
            # environment with autoescaping turned on
            node = nodes.MarkSafeIfAutoescape(node)
            if variables:
                node = nodes.Mod(node, nodes.Dict([
                    nodes.Pair(nodes.Const(key), value)
                    for key, value in variables.items()
                ]))
        return nodes.Output([node])
    def parse(self, parser):
        # Tag information
        token = next(parser.stream)
        lineno = token.lineno
        tag = token.value

        if tag == DJEDI_INIT_TAG:
            return [
                node.set_lineno(lineno) for node in self.create_node_storage()
            ]

        # Parse arguments
        uri = parser.parse_expression()
        params = self.parse_params(parser)
        body = []

        # If this is a blocknode, parse the body too.
        if tag == DJEDI_BLOCK_TAG:
            body = parser.parse_statements(
                ['name:end{}'.format(DJEDI_BLOCK_TAG)], drop_needle=True)
            if body:
                default = body[0].nodes[0].data.rstrip('\n\r ')
                default = textwrap.dedent(default)
                default = nodes.Const(default)
            else:
                default = nodes.Const(None)
        else:
            default = params.pop('default', nodes.Const(None))
        edit = params.pop('edit', nodes.Const(True))

        # If we got passed const values, we can buffer nodes before render.
        can_buffer = all([isinstance(n, nodes.Const) for n in (uri, default)])
        if can_buffer:
            node_or_uri = self.buffer_node(parser, uri, default)
        else:
            node_or_uri = uri

        params_dict = nodes.Dict([
            nodes.Pair(nodes.Const(key), value)
            for key, value in params.items()
        ])
        args = [node_or_uri, default, edit, params_dict, nodes.Const(tag)]

        return nodes.CallBlock(self.call_method('_render_node', args=args), [],
                               [], body).set_lineno(lineno)
    def parse(self, parser):
        stream = parser.stream

        tag = stream.next()

        # get view name
        if stream.current.test('string'):
            bundle_name = parser.parse_primary()
        else:
            bundle_name = parser.parse_expression()

        # get arguments
        args = []
        kwargs = []
        while not stream.current.test_any('block_end', 'name:as'):
            if args or kwargs:
                stream.expect('comma')
            if stream.current.test('name') and stream.look().test('assign'):
                key = nodes.Const(stream.next().value)
                stream.skip()
                value = parser.parse_expression()
                kwargs.append(nodes.Pair(key, value, lineno=key.lineno))
            else:
                args.append(parser.parse_expression())

        make_call_node = lambda *kw: \
            self.call_method('_build_tag',
                             args=[bundle_name,
                             nodes.List(args), nodes.Dict(kwargs)],
                             kwargs=kw)

        # if an as-clause is specified, write the result to context...
        if stream.next_if('name:as'):
            var = nodes.Name(stream.expect('name').value, 'store')
            call_node = make_call_node(
                nodes.Keyword('fail', nodes.Const(False)))
            return nodes.Assign(var, call_node)
        # ...otherwise print it out.
        else:
            return nodes.Output([make_call_node()]).set_lineno(tag.lineno)
Exemple #5
0
    def parse(self, parser):
        stream = parser.stream
        tag = next(stream)
        # get arguments
        args = []
        kwargs = []
        while not stream.current.test_any('block_end'):
            if args or kwargs:
                stream.expect('comma')
            if stream.current.test('name') and stream.look().test('assign'):
                key = nodes.Const(next(stream).value)
                stream.skip()
                value = parser.parse_expression()
                kwargs.append(nodes.Pair(key, value, lineno=key.lineno))
            else:
                args.append(parser.parse_expression())

        def make_call_node(*kw):
            return self.call_method('_call', args=[
                nodes.List(args),
                nodes.Dict(kwargs),
            ], kwargs=kw)

        return nodes.Output([make_call_node()]).set_lineno(tag.lineno)
Exemple #6
0
    def parse(self, parser):
        lineno = parser.stream.next().lineno

        # extract the language if available
        # Any additional parameters are passed to HtmlFormatter
        lang = None
        parameters = []
        while parser.stream.current.type != 'block_end':
            if lang or parameters:
                parser.stream.expect('comma')

            name = parser.stream.expect('name')
            if name.value in parameters or (name.value == 'lang' and lang):
                parser.fail('parameter %r defined twice.' % name.value,
                            name.lineno,
                            exc=TemplateAssertionError)

            if parser.stream.current.type == 'assign':
                next(parser.stream)
                if name.value == 'lang':
                    lang = parser.parse_expression()
                else:
                    parameters.append(
                        nodes.Pair(nodes.Const(name.value),
                                   parser.parse_expression()))

        if lang == None:
            lang = nodes.Const(None)
        parameters = nodes.Dict(parameters)

        # body of the block
        body = parser.parse_statements(['name:endhighlight'], drop_needle=True)

        return nodes.CallBlock(
            self.call_method('_highlight', [lang, parameters]), [], [],
            body).set_lineno(lineno)
Exemple #7
0
    def parse(self, parser):
        """Parse a translatable tag."""
        lineno = next(parser.stream).lineno

        # find all the variables referenced.  Additionally a variable can be
        # defined in the body of the trans block too, but this is checked at
        # a later state.
        plural_expr = None
        variables = {}
        while parser.stream.current.type != 'block_end':
            if variables:
                parser.stream.expect('comma')

            # skip colon for python compatibility
            if parser.stream.skip_if('colon'):
                break

            name = parser.stream.expect('name')
            if name.value in variables:
                parser.fail('translatable variable %r defined twice.' %
                            name.value,
                            name.lineno,
                            exc=TemplateAssertionError)

            # expressions
            if parser.stream.current.type == 'assign':
                next(parser.stream)
                variables[name.value] = var = parser.parse_expression()
            else:
                variables[name.value] = var = nodes.Name(name.value, 'load')
            if plural_expr is None:
                plural_expr = var

        parser.stream.expect('block_end')

        plural = plural_names = None
        have_plural = False
        referenced = set()

        # now parse until endtrans or pluralize
        singular_names, singular = self._parse_block(parser, True)
        if singular_names:
            referenced.update(singular_names)
            if plural_expr is None:
                plural_expr = nodes.Name(singular_names[0], 'load')

        # if we have a pluralize block, we parse that too
        if parser.stream.current.test('name:pluralize'):
            have_plural = True
            next(parser.stream)
            if parser.stream.current.type != 'block_end':
                name = parser.stream.expect('name')
                if name.value not in variables:
                    parser.fail('unknown variable %r for pluralization' %
                                name.value,
                                name.lineno,
                                exc=TemplateAssertionError)
                plural_expr = variables[name.value]
            parser.stream.expect('block_end')
            plural_names, plural = self._parse_block(parser, False)
            next(parser.stream)
            referenced.update(plural_names)
        else:
            next(parser.stream)

        # register free names as simple name expressions
        for var in referenced:
            if var not in variables:
                variables[var] = nodes.Name(var, 'load')

        # no variables referenced?  no need to escape
        if not referenced:
            singular = singular.replace('%%', '%')
            if plural:
                plural = plural.replace('%%', '%')

        if not have_plural:
            plural_expr = None
        elif plural_expr is None:
            parser.fail('pluralize without variables', lineno)

        if variables:
            variables = nodes.Dict([
                nodes.Pair(nodes.Const(x, lineno=lineno), y)
                for x, y in variables.items()
            ])
        else:
            variables = None

        node = self._make_node(singular, plural, variables, plural_expr)
        node.set_lineno(lineno)
        return node
Exemple #8
0
    def parse(self, parser):
        stream = parser.stream

        tag = stream.next()

        # get view name
        if stream.current.test('string'):
            # Need to work around Jinja2 syntax here. Jinja by default acts
            # like Python and concats subsequent strings. In this case
            # though, we want {% url "app.views.post" "1" %} to be treated
            # as view + argument, while still supporting
            # {% url "app.views.post"|filter %}. Essentially, what we do is
            # rather than let ``parser.parse_primary()`` deal with a "string"
            # token, we do so ourselves, and let parse_expression() handle all
            # other cases.
            if stream.look().test('string'):
                token = stream.next()
                viewname = nodes.Const(token.value, lineno=token.lineno)
            else:
                viewname = parser.parse_expression()
        else:
            # parse valid tokens and manually build a string from them
            bits = []
            name_allowed = True
            while True:
                if stream.current.test_any('dot', 'sub', 'colon'):
                    bits.append(stream.next())
                    name_allowed = True
                elif stream.current.test('name') and name_allowed:
                    bits.append(stream.next())
                    name_allowed = False
                else:
                    break
            viewname = nodes.Const("".join([b.value for b in bits]))
            if not bits:
                raise TemplateSyntaxError(
                    "'%s' requires path to view" % tag.value, tag.lineno)

        # get arguments
        args = []
        kwargs = []
        while not stream.current.test_any('block_end', 'name:as'):
            if args or kwargs:
                stream.expect('comma')
            if stream.current.test('name') and stream.look().test('assign'):
                key = nodes.Const(stream.next().value)
                stream.skip()
                value = parser.parse_expression()
                kwargs.append(nodes.Pair(key, value, lineno=key.lineno))
            else:
                args.append(parser.parse_expression())

        def make_call_node(*kw):
            return self.call_method('_reverse',
                                    args=[
                                        viewname,
                                        nodes.List(args),
                                        nodes.Dict(kwargs),
                                        nodes.Name('_current_app', 'load'),
                                    ],
                                    kwargs=kw)

        # if an as-clause is specified, write the result to context...
        if stream.next_if('name:as'):
            var = nodes.Name(stream.expect('name').value, 'store')
            call_node = make_call_node(
                nodes.Keyword('fail', nodes.Const(False)))
            return nodes.Assign(var, call_node)
        # ...otherwise print it out.
        else:
            return nodes.Output([make_call_node()]).set_lineno(tag.lineno)
    def _parse_blocktrans(self, parser, lineno):
        with_vars = {}
        count = None
        context = None
        trimmed = False
        as_var = None

        if parser.stream.skip_if('name:trimmed'):
            trimmed = True

        if parser.stream.skip_if('name:asvar'):
            as_var = parser.stream.expect(lexer.TOKEN_NAME)
            as_var = nodes.Name(as_var.value, 'store', lineno=as_var.lineno)

        if parser.stream.skip_if('name:with'):
            while parser.stream.look().type == lexer.TOKEN_ASSIGN:
                token = parser.stream.expect(lexer.TOKEN_NAME)
                key = token.value
                next(parser.stream)
                with_vars[key] = parser.parse_expression(False)

        if parser.stream.skip_if('name:count'):
            name = parser.stream.expect(lexer.TOKEN_NAME).value
            parser.stream.expect(lexer.TOKEN_ASSIGN)
            value = parser.parse_expression(False)
            count = (name, value)

        if parser.stream.skip_if('name:context'):
            context = parser.stream.expect(lexer.TOKEN_STRING).value

        parser.stream.expect(lexer.TOKEN_BLOCK_END)

        body_singular = None
        body = []
        additional_vars = set()
        for token in parser.stream:
            if token is lexer.TOKEN_EOF:
                parser.fail(
                    'unexpected end of template, expected endblocktrans tag')
            if token.type is lexer.TOKEN_DATA:
                body.append(token.value)
            elif token.type is lexer.TOKEN_VARIABLE_BEGIN:
                name = parser.stream.expect(lexer.TOKEN_NAME).value
                if name not in with_vars and (count is None
                                              or count[0] != name):
                    additional_vars.add(name)
                parser.stream.expect(lexer.TOKEN_VARIABLE_END)
                # django converts variables inside the blocktrans tag into
                # "%(var_name)s" format, so we do the same.
                body.append('%({})s'.format(name))
            elif token.type is lexer.TOKEN_BLOCK_BEGIN:
                if body_singular is None and parser.stream.skip_if(
                        'name:plural'):
                    if count is None:
                        parser.fail('used plural without specifying count')
                    parser.stream.expect(lexer.TOKEN_BLOCK_END)
                    body_singular = body
                    body = []
                else:
                    parser.stream.expect('name:endblocktrans')
                    break

        if count is not None and body_singular is None:
            parser.fail('plural form not found')

        trans_vars = [
            nodes.Pair(nodes.Const(key), val, lineno=lineno)
            for key, val in with_vars.items()
        ]

        if count is not None:
            trans_vars.append(
                nodes.Pair(nodes.Const(count[0]), count[1], lineno=lineno))

        trans_vars.extend(
            nodes.Pair(nodes.Const(key),
                       nodes.Name(key, 'load', lineno=lineno),
                       lineno=lineno) for key in additional_vars)

        kwargs = [
            nodes.Keyword('trans_vars',
                          nodes.Dict(trans_vars, lineno=lineno),
                          lineno=lineno)
        ]

        if context is not None:
            kwargs.append(
                nodes.Keyword('context',
                              nodes.Const(context, lineno=lineno),
                              lineno=lineno))
        if count is not None:
            kwargs.append(
                nodes.Keyword('count_var',
                              nodes.Const(count[0], lineno=lineno),
                              lineno=lineno))

        body = ''.join(body)
        if trimmed:
            body = ' '.join(map(lambda s: s.strip(),
                                body.strip().splitlines()))

        if body_singular is not None:
            body_singular = ''.join(body_singular)
            if trimmed:
                body_singular = ' '.join(
                    map(lambda s: s.strip(),
                        body_singular.strip().splitlines()))

        if body_singular is None:
            args = []
        else:
            args = [nodes.TemplateData(body_singular, lineno=lineno)]
        args.append(nodes.TemplateData(body, lineno=lineno))
        call = nodes.MarkSafe(self.call_method('_make_blocktrans', args,
                                               kwargs),
                              lineno=lineno)

        if as_var is None:
            return nodes.Output([call], lineno=lineno)
        else:
            return nodes.Assign(as_var, call)
Exemple #10
0
 def to_node_dict(cls, d):
     return nodes.Dict([nodes.Pair(nodes.Const(k), v if isinstance(v, nodes.Const) else nodes.Const(v)) for k,v in d.items()])
    def parse(self, parser):
        # Get the component for the tag name that we matched on
        tag_name = parser.stream.current[2]
        component_class = self.environment.components[tag_name]
        field_names = [f.name for f in dataclasses.fields(component_class)]
        has_children = CHILDREN_FIELD_NAME in field_names

        lineno = next(parser.stream).lineno

        node = nodes.Scope(lineno=lineno)

        # list of `Pair` nodes for tag properties to update "component" dictionary
        component_dict_update_items = []

        while parser.stream.current.type != 'block_end':
            lineno = parser.stream.current.lineno
            if component_dict_update_items:
                parser.stream.expect('comma')
            name = parser.stream.expect('name')
            parser.stream.expect('assign')
            value = parser.parse_expression()
            component_dict_update_items.append(
                nodes.Pair(nodes.Const(name.value), value))

        # dictionary initialization in the "component" name
        prepare_component_dict = [
            self._initialize_component_dict(component_class, lineno)
        ]

        if component_dict_update_items:
            component_dict_delta = nodes.Dict(component_dict_update_items)
            # `Getattr` for "update" function of the dictionary "component"
            update_component_dict_fun = nodes.Getattr(
                nodes.Name(TMP_COMPONENT_DICT_NAME, 'load'), 'update', 'load')
            # `Call` for `component.update(<prop name>, <prop value>)`
            call_component_dict_update = nodes.Call(update_component_dict_fun,
                                                    [component_dict_delta], [],
                                                    None, None)
            prepare_component_dict.append(
                nodes.ExprStmt(call_component_dict_update))

        # assign `component = __component` and `__component = None`
        prepare_component_dict.extend([
            nodes.Assign(nodes.Name(COMPONENT_DICT_NAME,
                                    'store',
                                    lineno=lineno),
                         nodes.Name(TMP_COMPONENT_DICT_NAME,
                                    'load',
                                    lineno=lineno),
                         lineno=lineno),
            nodes.Assign(nodes.Name(TMP_COMPONENT_DICT_NAME,
                                    'store',
                                    lineno=lineno),
                         nodes.Const(None, lineno=lineno),
                         lineno=lineno)
        ])

        if has_children:
            inner_block = list(
                parser.parse_statements(('name:end' + tag_name, ),
                                        drop_needle=True))
            # create children() macro
            children_macro = nodes.Macro()
            children_macro.name = CHILDREN_MACRO_NAME
            children_macro.args = []
            children_macro.defaults = []
            children_macro.body = inner_block
            children_macro_nodes = [children_macro]
        else:
            children_macro_nodes = []

        # include tag template
        include_tag = nodes.Include()
        # use `template` item of the "component" dictionary for template path
        include_tag.template = nodes.Getitem(nodes.Name(COMPONENT_DICT_NAME,
                                                        'load',
                                                        lineno=lineno),
                                             nodes.Const(TEMPLATE_FIELD_NAME,
                                                         lineno=lineno),
                                             'load',
                                             lineno=lineno)
        include_tag.ignore_missing = False
        include_tag.with_context = True

        node.body = prepare_component_dict + children_macro_nodes + [
            include_tag,
        ]

        return node
 def pair_node_for_field(name, value):
     return nodes.Pair(nodes.Const(name, lineno=lineno),
                       nodes.Const(value, lineno=lineno),
                       lineno=lineno)