def parse_primary(self, with_postfix=True):
     token = self.stream.current
     if token.type == 'name':
         if token.value in ('true', 'false', 'True', 'False'):
             node = nodes.Const(token.value in ('true', 'True'),
                                lineno=token.lineno)
         elif token.value in ('none', 'None'):
             node = nodes.Const(None, lineno=token.lineno)
         else:
             node = nodes.Name(token.value, 'load', lineno=token.lineno)
         next(self.stream)
     elif token.type == 'string':
         next(self.stream)
         buf = [token.value]
         lineno = token.lineno
         while self.stream.current.type == 'string':
             buf.append(self.stream.current.value)
             next(self.stream)
         node = nodes.Const(''.join(buf), lineno=lineno)
     elif token.type in ('integer', 'float'):
         next(self.stream)
         node = nodes.Const(token.value, lineno=token.lineno)
     elif token.type == 'lparen':
         next(self.stream)
         node = self.parse_tuple()
         self.stream.expect('rparen')
     elif token.type == 'lbracket':
         node = self.parse_list()
     elif token.type == 'lbrace':
         node = self.parse_dict()
     else:
         self.fail("unexpected token '%s'" % (token, ), token.lineno)
     if with_postfix:
         node = self.parse_postfix(node)
     return node
 def parse_assign_target(self,
                         with_tuple=True,
                         name_only=False,
                         extra_end_rules=None):
     """Parse an assignment target.  As Jinja2 allows assignments to
     tuples, this function can parse all allowed assignment targets.  Per
     default assignments to tuples are parsed, that can be disable however
     by setting `with_tuple` to `False`.  If only assignments to names are
     wanted `name_only` can be set to `True`.  The `extra_end_rules`
     parameter is forwarded to the tuple parsing function.
     """
     if name_only:
         token = self.stream.expect('name')
         target = nodes.Name(token.value, 'store', lineno=token.lineno)
     else:
         if with_tuple:
             target = self.parse_tuple(simplified=True,
                                       extra_end_rules=extra_end_rules)
         else:
             target = self.parse_primary(with_postfix=False)
         target.set_ctx('store')
     if not target.can_assign():
         self.fail(
             'can\'t assign to %r' % target.__class__.__name__.lower(),
             target.lineno)
     return target
    def _make_node(self, singular, plural, variables, plural_expr):
        """Generates a useful node from the data provided."""
        # 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)

        # mark the return value as safe if we are in an
        # environment with autoescaping turned on
        if self.environment.autoescape:
            node = nodes.MarkSafe(node)

        if variables:
            node = nodes.Mod(node, variables)
        return nodes.Output([node])
    def compile_expression(self, source, undefined_to_none=True):
        """A handy helper method that returns a callable that accepts keyword
        arguments that appear as variables in the expression.  If called it
        returns the result of the expression.

        This is useful if applications want to use the same rules as Jinja
        in template "configuration files" or similar situations.

        Example usage:

        >>> env = Environment()
        >>> expr = env.compile_expression('foo == 42')
        >>> expr(foo=23)
        False
        >>> expr(foo=42)
        True

        Per default the return value is converted to `None` if the
        expression returns an undefined value.  This can be changed
        by setting `undefined_to_none` to `False`.

        >>> env.compile_expression('var')() is None
        True
        >>> env.compile_expression('var', undefined_to_none=False)()
        Undefined

        **new in Jinja 2.1**
        """
        parser = Parser(self, source, state='variable')
        exc_info = None
        try:
            expr = parser.parse_expression()
            if not parser.stream.eos:
                raise TemplateSyntaxError('chunk after expression',
                                          parser.stream.current.lineno, None,
                                          None)
        except TemplateSyntaxError:
            exc_info = sys.exc_info()
        if exc_info is not None:
            self.handle_exception(exc_info, source_hint=source)
        body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)]
        template = self.from_string(nodes.Template(body, lineno=1))
        return TemplateExpression(template, undefined_to_none)
    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