def parse(self, parser): lineno = next(parser.stream).lineno url = parser.parse_expression(with_condexpr=False) url_var = nodes.Name('checked_url', 'store') args = None if parser.stream.current.type != 'block_end': parser.stream.expect('comma') args = parser.parse_expression(with_condexpr=False) fun_var = parser.free_identifier() body = parser.parse_statements(('name:endauth', 'name:else')) token = next(parser.stream) if token.test('name:else'): else_ = parser.parse_statements( ('name:endauth', ), drop_needle=True) else: else_ = None url_fun_tuple = nodes.Tuple([url_var, fun_var], 'store') # The url goes in the dyn_args (its not visited otherwise). # To be in the dyn_args, it must be wrapped in a Tuple. assignment = nodes.Assign(url_fun_tuple, self.call_method( 'template_if_auth_url_for', dyn_args=nodes.Tuple([url], 'load'), dyn_kwargs=args)).set_lineno(lineno) returned_ast = [assignment] if_node = nodes.If() if_node.test = nodes.Name('checked_url', 'load') if_node.body = body if_node.else_ = else_ if_node.elif_ = [] returned_ast.append(if_node.set_lineno(lineno)) return returned_ast
def parse_subscript(self, node): token = next(self.stream) if token.type == 'dot': attr_token = self.stream.current next(self.stream) if attr_token.type == 'name': return nodes.Getattr(node, attr_token.value, 'load', lineno=token.lineno) elif attr_token.type != 'integer': self.fail('expected name or number', attr_token.lineno) arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) return nodes.Getitem(node, arg, 'load', lineno=token.lineno) if token.type == 'lbracket': args = [] while self.stream.current.type != 'rbracket': if args: self.stream.expect('comma') args.append(self.parse_subscribed()) self.stream.expect('rbracket') if len(args) == 1: arg = args[0] else: arg = nodes.Tuple(args, 'load', lineno=token.lineno) return nodes.Getitem(node, arg, 'load', lineno=token.lineno) self.fail('expected subscript expression', self.lineno)
def parse_tuple(self, simplified=False, with_condexpr=True, extra_end_rules=None, explicit_parentheses=False): lineno = self.stream.current.lineno if simplified: parse = self.parse_primary elif with_condexpr: parse = self.parse_expression else: parse = lambda: self.parse_expression(with_condexpr=False) args = [] is_tuple = False while 1: if args: self.stream.expect('comma') if self.is_tuple_end(extra_end_rules): break args.append(parse()) if self.stream.current.type == 'comma': is_tuple = True else: break lineno = self.stream.current.lineno if not is_tuple: if args: return args[0] if not explicit_parentheses: self.fail("Expected an expression, got '%s'" % describe_token(self.stream.current)) return nodes.Tuple(args, 'load', lineno=lineno)
def parse_subscript(self, node): token = next(self.stream) if token.type == "dot": attr_token = self.stream.current next(self.stream) if attr_token.type == "name": return nodes.Getattr(node, attr_token.value, "load", lineno=token.lineno) elif attr_token.type != "integer": self.fail("expected name or number", attr_token.lineno) arg = nodes.Const(attr_token.value, lineno=attr_token.lineno) return nodes.Getitem(node, arg, "load", lineno=token.lineno) if token.type == "lbracket": args = [] while self.stream.current.type != "rbracket": if args: self.stream.expect("comma") args.append(self.parse_subscribed()) self.stream.expect("rbracket") if len(args) == 1: arg = args[0] else: arg = nodes.Tuple(args, "load", lineno=token.lineno) return nodes.Getitem(node, arg, "load", lineno=token.lineno) self.fail("expected subscript expression", self.lineno)
def parse_tuple( self, simplified=False, with_condexpr=True, extra_end_rules=None, explicit_parentheses=False, ): """Works like `parse_expression` but if multiple expressions are delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. This method could also return a regular expression instead of a tuple if no commas where found. The default parsing mode is a full tuple. If `simplified` is `True` only names and literals are parsed. The `no_condexpr` parameter is forwarded to :meth:`parse_expression`. Because tuples do not require delimiters and may end in a bogus comma an extra hint is needed that marks the end of a tuple. For example for loops support tuples between `for` and `in`. In that case the `extra_end_rules` is set to ``['name:in']``. `explicit_parentheses` is true if the parsing was triggered by an expression in parentheses. This is used to figure out if an empty tuple is a valid expression or not. """ lineno = self.stream.current.lineno if simplified: parse = self.parse_primary elif with_condexpr: parse = self.parse_expression else: parse = lambda: self.parse_expression(with_condexpr=False) args = [] is_tuple = False while 1: if args: self.stream.expect("comma") if self.is_tuple_end(extra_end_rules): break args.append(parse()) if self.stream.current.type == "comma": is_tuple = True else: break lineno = self.stream.current.lineno if not is_tuple: if args: return args[0] # if we don't have explicit parentheses, an empty tuple is # not a valid expression. This would mean nothing (literally # nothing) in the spot of an expression would be an empty # tuple. if not explicit_parentheses: self.fail("Expected an expression, got '%s'" % describe_token(self.stream.current)) return nodes.Tuple(args, "load", lineno=lineno)
def create_tuple(self, *values, **kwargs): ctx = kwargs.get('ctx', 'local') node = kwargs.get('node', nodes.Const) node_args = kwargs.get('node_args', []) values = [ node(v, *node_args) if isinstance(v, str) else v for v in values ] return nodes.Tuple(values, ctx)
def parse_tuple(self, simplified=False, with_condexpr=True, extra_end_rules=None): """Works like `parse_expression` but if multiple expressions are delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created. This method could also return a regular expression instead of a tuple if no commas where found. The default parsing mode is a full tuple. If `simplified` is `True` only names and literals are parsed. The `no_condexpr` parameter is forwarded to :meth:`parse_expression`. Because tuples do not require delimiters and may end in a bogus comma an extra hint is needed that marks the end of a tuple. For example for loops support tuples between `for` and `in`. In that case the `extra_end_rules` is set to ``['name:in']``. """ lineno = self.stream.current.lineno if simplified: parse = lambda: self.parse_primary(with_postfix=False) elif with_condexpr: parse = self.parse_expression else: parse = lambda: self.parse_expression(with_condexpr=False) args = [] is_tuple = False while 1: if args: self.stream.expect('comma') if self.is_tuple_end(extra_end_rules): break args.append(parse()) if self.stream.current.type == 'comma': is_tuple = True else: break lineno = self.stream.current.lineno if not is_tuple and args: return args[0] return nodes.Tuple(args, 'load', lineno=lineno)
def parse(self, parser): lineno = next(parser.stream).lineno # Get the block selection from the tag argument. block_selection = parser.parse_expression() # Make "Name" node for "For" node target. block_name = nodes.Name('_ext_ob_blknm', 'store') # For each block, add an "If" node checking if it matches the target. # Also record the original "default" ordering of the blocks. blocks = [] block_names = [] for node in parser.parse_statements(['name:endorderblocks'], drop_needle=True): if isinstance(node, nodes.Block): blocks.append(nodes.If( nodes.Compare( block_name, [nodes.Operand('eq', nodes.Const(node.name))]), [node], [])) block_names.append(node.name) # Make a "For" node iterating over the given block selection. If the # block selection is undefined or None then use the original ordering. return nodes.For( block_name, nodes.CondExpr( nodes.And( nodes.Test(block_selection, 'defined', [], [], None, None), nodes.Not( nodes.Test(block_selection, 'none', [], [], None, None)), ), block_selection, nodes.Tuple([nodes.Const(x) for x in block_names], 'store')), blocks, [], None, False)