From a3aa821a5f3b3cffd7a166ead8794279d8cc645c Mon Sep 17 00:00:00 2001 From: Kevin Brown Date: Sat, 16 May 2020 15:55:56 -0400 Subject: Add proper parsing for {% for %} parameters Previously a lot of the parsing was done through implicit variable tuples, but that ended up causing a lot of special cases because we were only allowing variables in those tuples. Now that we are going to move towards having tuples be handled consitently, whether they are identifier tuples or tuple literals, the logic for handling the `{% for %}` block needed to be cleaned up. --- src/jinja2/new_parser.py | 88 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/src/jinja2/new_parser.py b/src/jinja2/new_parser.py index ea1117b..6d0fb90 100644 --- a/src/jinja2/new_parser.py +++ b/src/jinja2/new_parser.py @@ -233,7 +233,6 @@ def parse_block_filter(ast): ) def parse_block_for(ast): - target = None iter = None body = ast['contents'] else_ = [] @@ -242,39 +241,76 @@ def parse_block_for(ast): block_parameters = ast['start']['parameters'] - if block_parameters[0]['value']['operator'] == 'in': - block_parameters[0:1] = [ - { - "value": block_parameters[0]['value']['left'] - }, - { - "value": { - "variable": "in" - } - }, - { - "value": block_parameters[0]['value']['right'] - }, - ] + target = [] + for param_number, param in enumerate(block_parameters): + if param['value']['variable'] == 'in': + break + + if param['value']['operator'] == 'in': + block_parameters[param_number:param_number + 1] = [ + { + "value": param['value']['left'] + }, + { + "value": { + "variable": "in" + } + }, + { + "value": param['value']['right'] + }, + ] + + target.append( + parse_variable( + param['value']['left'], + variable_context='store' + ) + ) - if block_parameters[1]['value']['variable'] != 'in': - raise + break - target = parse_variable(block_parameters[0]['value'], variable_context='store') - iter = parse_variable(block_parameters[2]['value']) + target.append(parse_variable(param['value'], variable_context='store')) + + if len(target) == 0: + raise TemplateSyntaxError( + "expected token 'in'", + lineno=lineno_from_parseinfo(ast['start']['parseinfo']) + ) - if not isinstance(target, (nodes.Name, nodes.Tuple)): + if len(target) == len(block_parameters): raise TemplateSyntaxError( "expected token 'in'", - lineno=target.lineno + lineno=target[1].lineno ) - if len(block_parameters) > 3: - if block_parameters[3]['value']['variable'] == 'if': - test = parse_conditional_expression(block_parameters[4]['value']) + if len(target) == 1: + target = target[0] + else: + target = nodes.Tuple( + target, + 'store', + lineno=target[0].lineno + ) + param_number += 2 + + iter = parse_variable(block_parameters[param_number]['value']) + param_number += 1 + + if len(block_parameters) > param_number + 1: + if block_parameters[param_number]['value']['variable'] == 'if': + param_number += 1 + + test = parse_conditional_expression( + block_parameters[param_number]['value'] + ) + param_number += 1 + + if len(block_parameters) > param_number + 2: + raise - if len(block_parameters) > 3: - recursive = block_parameters[-1]['value']['variable'] == 'recursive' + if len(block_parameters) == param_number + 1: + recursive = block_parameters[param_number]['value']['variable'] == 'recursive' else_ = _split_contents_at_block(ast['contents'], 'else') -- cgit v1.2.1