NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

parser.py (29506B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\jinja2\parser.py
      2 from jinja2 import nodes
      3 from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
      4 from jinja2.utils import next
      5 from jinja2.lexer import describe_token, describe_token_expr
      6 _statement_keywords = frozenset(['for',
      7  'if',
      8  'block',
      9  'extends',
     10  'print',
     11  'macro',
     12  'include',
     13  'from',
     14  'import',
     15  'set'])
     16 _compare_operators = frozenset(['eq',
     17  'ne',
     18  'lt',
     19  'lteq',
     20  'gt',
     21  'gteq'])
     22 
     23 class Parser(object):
     24 
     25     def __init__(self, environment, source, name = None, filename = None, state = None):
     26         self.environment = environment
     27         self.stream = environment._tokenize(source, name, filename, state)
     28         self.name = name
     29         self.filename = filename
     30         self.closed = False
     31         self.extensions = {}
     32         for extension in environment.iter_extensions():
     33             for tag in extension.tags:
     34                 self.extensions[tag] = extension.parse
     35 
     36         self._last_identifier = 0
     37         self._tag_stack = []
     38         self._end_token_stack = []
     39 
     40     def fail(self, msg, lineno = None, exc = TemplateSyntaxError):
     41         if lineno is None:
     42             lineno = self.stream.current.lineno
     43         raise exc(msg, lineno, self.name, self.filename)
     44 
     45     def _fail_ut_eof(self, name, end_token_stack, lineno):
     46         expected = []
     47         for exprs in end_token_stack:
     48             expected.extend(map(describe_token_expr, exprs))
     49 
     50         if end_token_stack:
     51             currently_looking = ' or '.join(("'%s'" % describe_token_expr(expr) for expr in end_token_stack[-1]))
     52         else:
     53             currently_looking = None
     54         if name is None:
     55             message = ['Unexpected end of template.']
     56         else:
     57             message = ["Encountered unknown tag '%s'." % name]
     58         if currently_looking:
     59             if name is not None and name in expected:
     60                 message.append('You probably made a nesting mistake. Jinja is expecting this tag, but currently looking for %s.' % currently_looking)
     61             else:
     62                 message.append('Jinja was looking for the following tags: %s.' % currently_looking)
     63         if self._tag_stack:
     64             message.append("The innermost block that needs to be closed is '%s'." % self._tag_stack[-1])
     65         self.fail(' '.join(message), lineno)
     66 
     67     def fail_unknown_tag(self, name, lineno = None):
     68         return self._fail_ut_eof(name, self._end_token_stack, lineno)
     69 
     70     def fail_eof(self, end_tokens = None, lineno = None):
     71         stack = list(self._end_token_stack)
     72         if end_tokens is not None:
     73             stack.append(end_tokens)
     74         return self._fail_ut_eof(None, stack, lineno)
     75 
     76     def is_tuple_end(self, extra_end_rules = None):
     77         if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
     78             return True
     79         if extra_end_rules is not None:
     80             return self.stream.current.test_any(extra_end_rules)
     81         return False
     82 
     83     def free_identifier(self, lineno = None):
     84         self._last_identifier += 1
     85         rv = object.__new__(nodes.InternalName)
     86         nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
     87         return rv
     88 
     89     def parse_statement(self):
     90         token = self.stream.current
     91         if token.type != 'name':
     92             self.fail('tag name expected', token.lineno)
     93         self._tag_stack.append(token.value)
     94         pop_tag = True
     95         try:
     96             if token.value in _statement_keywords:
     97                 return getattr(self, 'parse_' + self.stream.current.value)()
     98             if token.value == 'call':
     99                 return self.parse_call_block()
    100             if token.value == 'filter':
    101                 return self.parse_filter_block()
    102             ext = self.extensions.get(token.value)
    103             if ext is not None:
    104                 return ext(self)
    105             self._tag_stack.pop()
    106             pop_tag = False
    107             self.fail_unknown_tag(token.value, token.lineno)
    108         finally:
    109             if pop_tag:
    110                 self._tag_stack.pop()
    111 
    112     def parse_statements(self, end_tokens, drop_needle = False):
    113         self.stream.skip_if('colon')
    114         self.stream.expect('block_end')
    115         result = self.subparse(end_tokens)
    116         if self.stream.current.type == 'eof':
    117             self.fail_eof(end_tokens)
    118         if drop_needle:
    119             next(self.stream)
    120         return result
    121 
    122     def parse_set(self):
    123         lineno = next(self.stream).lineno
    124         target = self.parse_assign_target()
    125         self.stream.expect('assign')
    126         expr = self.parse_tuple()
    127         return nodes.Assign(target, expr, lineno=lineno)
    128 
    129     def parse_for(self):
    130         lineno = self.stream.expect('name:for').lineno
    131         target = self.parse_assign_target(extra_end_rules=('name:in',))
    132         self.stream.expect('name:in')
    133         iter = self.parse_tuple(with_condexpr=False, extra_end_rules=('name:recursive',))
    134         test = None
    135         if self.stream.skip_if('name:if'):
    136             test = self.parse_expression()
    137         recursive = self.stream.skip_if('name:recursive')
    138         body = self.parse_statements(('name:endfor', 'name:else'))
    139         if next(self.stream).value == 'endfor':
    140             else_ = []
    141         else:
    142             else_ = self.parse_statements(('name:endfor',), drop_needle=True)
    143         return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
    144 
    145     def parse_if(self):
    146         node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
    147         while 1:
    148             node.test = self.parse_tuple(with_condexpr=False)
    149             node.body = self.parse_statements(('name:elif', 'name:else', 'name:endif'))
    150             token = next(self.stream)
    151             if token.test('name:elif'):
    152                 new_node = nodes.If(lineno=self.stream.current.lineno)
    153                 node.else_ = [new_node]
    154                 node = new_node
    155                 continue
    156             elif token.test('name:else'):
    157                 node.else_ = self.parse_statements(('name:endif',), drop_needle=True)
    158             else:
    159                 node.else_ = []
    160             break
    161 
    162         return result
    163 
    164     def parse_block(self):
    165         node = nodes.Block(lineno=next(self.stream).lineno)
    166         node.name = self.stream.expect('name').value
    167         node.scoped = self.stream.skip_if('name:scoped')
    168         if self.stream.current.type == 'sub':
    169             self.fail('Block names in Jinja have to be valid Python identifiers and may not contain hyphens, use an underscore instead.')
    170         node.body = self.parse_statements(('name:endblock',), drop_needle=True)
    171         self.stream.skip_if('name:' + node.name)
    172         return node
    173 
    174     def parse_extends(self):
    175         node = nodes.Extends(lineno=next(self.stream).lineno)
    176         node.template = self.parse_expression()
    177         return node
    178 
    179     def parse_import_context(self, node, default):
    180         if self.stream.current.test_any('name:with', 'name:without') and self.stream.look().test('name:context'):
    181             node.with_context = next(self.stream).value == 'with'
    182             self.stream.skip()
    183         else:
    184             node.with_context = default
    185         return node
    186 
    187     def parse_include(self):
    188         node = nodes.Include(lineno=next(self.stream).lineno)
    189         node.template = self.parse_expression()
    190         if self.stream.current.test('name:ignore') and self.stream.look().test('name:missing'):
    191             node.ignore_missing = True
    192             self.stream.skip(2)
    193         else:
    194             node.ignore_missing = False
    195         return self.parse_import_context(node, True)
    196 
    197     def parse_import(self):
    198         node = nodes.Import(lineno=next(self.stream).lineno)
    199         node.template = self.parse_expression()
    200         self.stream.expect('name:as')
    201         node.target = self.parse_assign_target(name_only=True).name
    202         return self.parse_import_context(node, False)
    203 
    204     def parse_from(self):
    205         node = nodes.FromImport(lineno=next(self.stream).lineno)
    206         node.template = self.parse_expression()
    207         self.stream.expect('name:import')
    208         node.names = []
    209 
    210         def parse_context():
    211             if self.stream.current.value in ('with', 'without') and self.stream.look().test('name:context'):
    212                 node.with_context = next(self.stream).value == 'with'
    213                 self.stream.skip()
    214                 return True
    215             return False
    216 
    217         while 1:
    218             if node.names:
    219                 self.stream.expect('comma')
    220             if self.stream.current.type == 'name':
    221                 if parse_context():
    222                     break
    223                 target = self.parse_assign_target(name_only=True)
    224                 if target.name.startswith('_'):
    225                     self.fail('names starting with an underline can not be imported', target.lineno, exc=TemplateAssertionError)
    226                 if self.stream.skip_if('name:as'):
    227                     alias = self.parse_assign_target(name_only=True)
    228                     node.names.append((target.name, alias.name))
    229                 else:
    230                     node.names.append(target.name)
    231                 if parse_context() or self.stream.current.type != 'comma':
    232                     break
    233             else:
    234                 break
    235 
    236         if not hasattr(node, 'with_context'):
    237             node.with_context = False
    238             self.stream.skip_if('comma')
    239         return node
    240 
    241     def parse_signature(self, node):
    242         node.args = args = []
    243         node.defaults = defaults = []
    244         self.stream.expect('lparen')
    245         while self.stream.current.type != 'rparen':
    246             if args:
    247                 self.stream.expect('comma')
    248             arg = self.parse_assign_target(name_only=True)
    249             arg.set_ctx('param')
    250             if self.stream.skip_if('assign'):
    251                 defaults.append(self.parse_expression())
    252             args.append(arg)
    253 
    254         self.stream.expect('rparen')
    255 
    256     def parse_call_block(self):
    257         node = nodes.CallBlock(lineno=next(self.stream).lineno)
    258         if self.stream.current.type == 'lparen':
    259             self.parse_signature(node)
    260         else:
    261             node.args = []
    262             node.defaults = []
    263         node.call = self.parse_expression()
    264         if not isinstance(node.call, nodes.Call):
    265             self.fail('expected call', node.lineno)
    266         node.body = self.parse_statements(('name:endcall',), drop_needle=True)
    267         return node
    268 
    269     def parse_filter_block(self):
    270         node = nodes.FilterBlock(lineno=next(self.stream).lineno)
    271         node.filter = self.parse_filter(None, start_inline=True)
    272         node.body = self.parse_statements(('name:endfilter',), drop_needle=True)
    273         return node
    274 
    275     def parse_macro(self):
    276         node = nodes.Macro(lineno=next(self.stream).lineno)
    277         node.name = self.parse_assign_target(name_only=True).name
    278         self.parse_signature(node)
    279         node.body = self.parse_statements(('name:endmacro',), drop_needle=True)
    280         return node
    281 
    282     def parse_print(self):
    283         node = nodes.Output(lineno=next(self.stream).lineno)
    284         node.nodes = []
    285         while self.stream.current.type != 'block_end':
    286             if node.nodes:
    287                 self.stream.expect('comma')
    288             node.nodes.append(self.parse_expression())
    289 
    290         return node
    291 
    292     def parse_assign_target(self, with_tuple = True, name_only = False, extra_end_rules = None):
    293         if name_only:
    294             token = self.stream.expect('name')
    295             target = nodes.Name(token.value, 'store', lineno=token.lineno)
    296         else:
    297             if with_tuple:
    298                 target = self.parse_tuple(simplified=True, extra_end_rules=extra_end_rules)
    299             else:
    300                 target = self.parse_primary()
    301             target.set_ctx('store')
    302         if not target.can_assign():
    303             self.fail("can't assign to %r" % target.__class__.__name__.lower(), target.lineno)
    304         return target
    305 
    306     def parse_expression(self, with_condexpr = True):
    307         if with_condexpr:
    308             return self.parse_condexpr()
    309         return self.parse_or()
    310 
    311     def parse_condexpr(self):
    312         lineno = self.stream.current.lineno
    313         expr1 = self.parse_or()
    314         while self.stream.skip_if('name:if'):
    315             expr2 = self.parse_or()
    316             if self.stream.skip_if('name:else'):
    317                 expr3 = self.parse_condexpr()
    318             else:
    319                 expr3 = None
    320             expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
    321             lineno = self.stream.current.lineno
    322 
    323         return expr1
    324 
    325     def parse_or(self):
    326         lineno = self.stream.current.lineno
    327         left = self.parse_and()
    328         while self.stream.skip_if('name:or'):
    329             right = self.parse_and()
    330             left = nodes.Or(left, right, lineno=lineno)
    331             lineno = self.stream.current.lineno
    332 
    333         return left
    334 
    335     def parse_and(self):
    336         lineno = self.stream.current.lineno
    337         left = self.parse_not()
    338         while self.stream.skip_if('name:and'):
    339             right = self.parse_not()
    340             left = nodes.And(left, right, lineno=lineno)
    341             lineno = self.stream.current.lineno
    342 
    343         return left
    344 
    345     def parse_not(self):
    346         if self.stream.current.test('name:not'):
    347             lineno = next(self.stream).lineno
    348             return nodes.Not(self.parse_not(), lineno=lineno)
    349         return self.parse_compare()
    350 
    351     def parse_compare(self):
    352         lineno = self.stream.current.lineno
    353         expr = self.parse_add()
    354         ops = []
    355         while 1:
    356             token_type = self.stream.current.type
    357             if token_type in _compare_operators:
    358                 next(self.stream)
    359                 ops.append(nodes.Operand(token_type, self.parse_add()))
    360             elif self.stream.skip_if('name:in'):
    361                 ops.append(nodes.Operand('in', self.parse_add()))
    362             elif self.stream.current.test('name:not') and self.stream.look().test('name:in'):
    363                 self.stream.skip(2)
    364                 ops.append(nodes.Operand('notin', self.parse_add()))
    365             else:
    366                 break
    367             lineno = self.stream.current.lineno
    368 
    369         if not ops:
    370             return expr
    371         return nodes.Compare(expr, ops, lineno=lineno)
    372 
    373     def parse_add(self):
    374         lineno = self.stream.current.lineno
    375         left = self.parse_sub()
    376         while self.stream.current.type == 'add':
    377             next(self.stream)
    378             right = self.parse_sub()
    379             left = nodes.Add(left, right, lineno=lineno)
    380             lineno = self.stream.current.lineno
    381 
    382         return left
    383 
    384     def parse_sub(self):
    385         lineno = self.stream.current.lineno
    386         left = self.parse_concat()
    387         while self.stream.current.type == 'sub':
    388             next(self.stream)
    389             right = self.parse_concat()
    390             left = nodes.Sub(left, right, lineno=lineno)
    391             lineno = self.stream.current.lineno
    392 
    393         return left
    394 
    395     def parse_concat(self):
    396         lineno = self.stream.current.lineno
    397         args = [self.parse_mul()]
    398         while self.stream.current.type == 'tilde':
    399             next(self.stream)
    400             args.append(self.parse_mul())
    401 
    402         if len(args) == 1:
    403             return args[0]
    404         return nodes.Concat(args, lineno=lineno)
    405 
    406     def parse_mul(self):
    407         lineno = self.stream.current.lineno
    408         left = self.parse_div()
    409         while self.stream.current.type == 'mul':
    410             next(self.stream)
    411             right = self.parse_div()
    412             left = nodes.Mul(left, right, lineno=lineno)
    413             lineno = self.stream.current.lineno
    414 
    415         return left
    416 
    417     def parse_div(self):
    418         lineno = self.stream.current.lineno
    419         left = self.parse_floordiv()
    420         while self.stream.current.type == 'div':
    421             next(self.stream)
    422             right = self.parse_floordiv()
    423             left = nodes.Div(left, right, lineno=lineno)
    424             lineno = self.stream.current.lineno
    425 
    426         return left
    427 
    428     def parse_floordiv(self):
    429         lineno = self.stream.current.lineno
    430         left = self.parse_mod()
    431         while self.stream.current.type == 'floordiv':
    432             next(self.stream)
    433             right = self.parse_mod()
    434             left = nodes.FloorDiv(left, right, lineno=lineno)
    435             lineno = self.stream.current.lineno
    436 
    437         return left
    438 
    439     def parse_mod(self):
    440         lineno = self.stream.current.lineno
    441         left = self.parse_pow()
    442         while self.stream.current.type == 'mod':
    443             next(self.stream)
    444             right = self.parse_pow()
    445             left = nodes.Mod(left, right, lineno=lineno)
    446             lineno = self.stream.current.lineno
    447 
    448         return left
    449 
    450     def parse_pow(self):
    451         lineno = self.stream.current.lineno
    452         left = self.parse_unary()
    453         while self.stream.current.type == 'pow':
    454             next(self.stream)
    455             right = self.parse_unary()
    456             left = nodes.Pow(left, right, lineno=lineno)
    457             lineno = self.stream.current.lineno
    458 
    459         return left
    460 
    461     def parse_unary(self, with_filter = True):
    462         token_type = self.stream.current.type
    463         lineno = self.stream.current.lineno
    464         if token_type == 'sub':
    465             next(self.stream)
    466             node = nodes.Neg(self.parse_unary(False), lineno=lineno)
    467         elif token_type == 'add':
    468             next(self.stream)
    469             node = nodes.Pos(self.parse_unary(False), lineno=lineno)
    470         else:
    471             node = self.parse_primary()
    472         node = self.parse_postfix(node)
    473         if with_filter:
    474             node = self.parse_filter_expr(node)
    475         return node
    476 
    477     def parse_primary(self):
    478         token = self.stream.current
    479         if token.type == 'name':
    480             if token.value in ('true', 'false', 'True', 'False'):
    481                 node = nodes.Const(token.value in ('true', 'True'), lineno=token.lineno)
    482             elif token.value in ('none', 'None'):
    483                 node = nodes.Const(None, lineno=token.lineno)
    484             else:
    485                 node = nodes.Name(token.value, 'load', lineno=token.lineno)
    486             next(self.stream)
    487         elif token.type == 'string':
    488             next(self.stream)
    489             buf = [token.value]
    490             lineno = token.lineno
    491             while self.stream.current.type == 'string':
    492                 buf.append(self.stream.current.value)
    493                 next(self.stream)
    494 
    495             node = nodes.Const(''.join(buf), lineno=lineno)
    496         elif token.type in ('integer', 'float'):
    497             next(self.stream)
    498             node = nodes.Const(token.value, lineno=token.lineno)
    499         elif token.type == 'lparen':
    500             next(self.stream)
    501             node = self.parse_tuple(explicit_parentheses=True)
    502             self.stream.expect('rparen')
    503         elif token.type == 'lbracket':
    504             node = self.parse_list()
    505         elif token.type == 'lbrace':
    506             node = self.parse_dict()
    507         else:
    508             self.fail("unexpected '%s'" % describe_token(token), token.lineno)
    509         return node
    510 
    511     def parse_tuple(self, simplified = False, with_condexpr = True, extra_end_rules = None, explicit_parentheses = False):
    512         lineno = self.stream.current.lineno
    513         if simplified:
    514             parse = self.parse_primary
    515         elif with_condexpr:
    516             parse = self.parse_expression
    517         else:
    518             parse = lambda : self.parse_expression(with_condexpr=False)
    519         args = []
    520         is_tuple = False
    521         while 1:
    522             if args:
    523                 self.stream.expect('comma')
    524             if self.is_tuple_end(extra_end_rules):
    525                 break
    526             args.append(parse())
    527             if self.stream.current.type == 'comma':
    528                 is_tuple = True
    529             else:
    530                 break
    531             lineno = self.stream.current.lineno
    532 
    533         if not is_tuple:
    534             if args:
    535                 return args[0]
    536             if not explicit_parentheses:
    537                 self.fail("Expected an expression, got '%s'" % describe_token(self.stream.current))
    538         return nodes.Tuple(args, 'load', lineno=lineno)
    539 
    540     def parse_list(self):
    541         token = self.stream.expect('lbracket')
    542         items = []
    543         while self.stream.current.type != 'rbracket':
    544             if items:
    545                 self.stream.expect('comma')
    546             if self.stream.current.type == 'rbracket':
    547                 break
    548             items.append(self.parse_expression())
    549 
    550         self.stream.expect('rbracket')
    551         return nodes.List(items, lineno=token.lineno)
    552 
    553     def parse_dict(self):
    554         token = self.stream.expect('lbrace')
    555         items = []
    556         while self.stream.current.type != 'rbrace':
    557             if items:
    558                 self.stream.expect('comma')
    559             if self.stream.current.type == 'rbrace':
    560                 break
    561             key = self.parse_expression()
    562             self.stream.expect('colon')
    563             value = self.parse_expression()
    564             items.append(nodes.Pair(key, value, lineno=key.lineno))
    565 
    566         self.stream.expect('rbrace')
    567         return nodes.Dict(items, lineno=token.lineno)
    568 
    569     def parse_postfix(self, node):
    570         while 1:
    571             token_type = self.stream.current.type
    572             if token_type == 'dot' or token_type == 'lbracket':
    573                 node = self.parse_subscript(node)
    574             elif token_type == 'lparen':
    575                 node = self.parse_call(node)
    576             else:
    577                 break
    578 
    579         return node
    580 
    581     def parse_filter_expr(self, node):
    582         while 1:
    583             token_type = self.stream.current.type
    584             if token_type == 'pipe':
    585                 node = self.parse_filter(node)
    586             elif token_type == 'name' and self.stream.current.value == 'is':
    587                 node = self.parse_test(node)
    588             elif token_type == 'lparen':
    589                 node = self.parse_call(node)
    590             else:
    591                 break
    592 
    593         return node
    594 
    595     def parse_subscript(self, node):
    596         token = next(self.stream)
    597         if token.type == 'dot':
    598             attr_token = self.stream.current
    599             next(self.stream)
    600             if attr_token.type == 'name':
    601                 return nodes.Getattr(node, attr_token.value, 'load', lineno=token.lineno)
    602             if attr_token.type != 'integer':
    603                 self.fail('expected name or number', attr_token.lineno)
    604             arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
    605             return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
    606         if token.type == 'lbracket':
    607             args = []
    608             while self.stream.current.type != 'rbracket':
    609                 if args:
    610                     self.stream.expect('comma')
    611                 args.append(self.parse_subscribed())
    612 
    613             self.stream.expect('rbracket')
    614             if len(args) == 1:
    615                 arg = args[0]
    616             else:
    617                 arg = nodes.Tuple(args, 'load', lineno=token.lineno)
    618             return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
    619         self.fail('expected subscript expression', self.lineno)
    620 
    621     def parse_subscribed(self):
    622         lineno = self.stream.current.lineno
    623         if self.stream.current.type == 'colon':
    624             next(self.stream)
    625             args = [None]
    626         else:
    627             node = self.parse_expression()
    628             if self.stream.current.type != 'colon':
    629                 return node
    630             next(self.stream)
    631             args = [node]
    632         if self.stream.current.type == 'colon':
    633             args.append(None)
    634         elif self.stream.current.type not in ('rbracket', 'comma'):
    635             args.append(self.parse_expression())
    636         else:
    637             args.append(None)
    638         if self.stream.current.type == 'colon':
    639             next(self.stream)
    640             if self.stream.current.type not in ('rbracket', 'comma'):
    641                 args.append(self.parse_expression())
    642             else:
    643                 args.append(None)
    644         else:
    645             args.append(None)
    646         return nodes.Slice(lineno=lineno, *args)
    647 
    648     def parse_call(self, node):
    649         token = self.stream.expect('lparen')
    650         args = []
    651         kwargs = []
    652         dyn_args = dyn_kwargs = None
    653         require_comma = False
    654 
    655         def ensure(expr):
    656             if not expr:
    657                 self.fail('invalid syntax for function call expression', token.lineno)
    658 
    659         while self.stream.current.type != 'rparen':
    660             if require_comma:
    661                 self.stream.expect('comma')
    662                 if self.stream.current.type == 'rparen':
    663                     break
    664             if self.stream.current.type == 'mul':
    665                 ensure(dyn_args is None and dyn_kwargs is None)
    666                 next(self.stream)
    667                 dyn_args = self.parse_expression()
    668             elif self.stream.current.type == 'pow':
    669                 ensure(dyn_kwargs is None)
    670                 next(self.stream)
    671                 dyn_kwargs = self.parse_expression()
    672             else:
    673                 ensure(dyn_args is None and dyn_kwargs is None)
    674                 if self.stream.current.type == 'name' and self.stream.look().type == 'assign':
    675                     key = self.stream.current.value
    676                     self.stream.skip(2)
    677                     value = self.parse_expression()
    678                     kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
    679                 else:
    680                     ensure(not kwargs)
    681                     args.append(self.parse_expression())
    682             require_comma = True
    683 
    684         self.stream.expect('rparen')
    685         if node is None:
    686             return (args,
    687              kwargs,
    688              dyn_args,
    689              dyn_kwargs)
    690         return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
    691 
    692     def parse_filter(self, node, start_inline = False):
    693         while self.stream.current.type == 'pipe' or start_inline:
    694             if not start_inline:
    695                 next(self.stream)
    696             token = self.stream.expect('name')
    697             name = token.value
    698             while self.stream.current.type == 'dot':
    699                 next(self.stream)
    700                 name += '.' + self.stream.expect('name').value
    701 
    702             if self.stream.current.type == 'lparen':
    703                 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
    704             else:
    705                 args = []
    706                 kwargs = []
    707                 dyn_args = dyn_kwargs = None
    708             node = nodes.Filter(node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
    709             start_inline = False
    710 
    711         return node
    712 
    713     def parse_test(self, node):
    714         token = next(self.stream)
    715         if self.stream.current.test('name:not'):
    716             next(self.stream)
    717             negated = True
    718         else:
    719             negated = False
    720         name = self.stream.expect('name').value
    721         while self.stream.current.type == 'dot':
    722             next(self.stream)
    723             name += '.' + self.stream.expect('name').value
    724 
    725         dyn_args = dyn_kwargs = None
    726         kwargs = []
    727         if self.stream.current.type == 'lparen':
    728             args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
    729         elif self.stream.current.type in ('name', 'string', 'integer', 'float', 'lparen', 'lbracket', 'lbrace') and not self.stream.current.test_any('name:else', 'name:or', 'name:and'):
    730             if self.stream.current.test('name:is'):
    731                 self.fail('You cannot chain multiple tests with is')
    732             args = [self.parse_expression()]
    733         else:
    734             args = []
    735         node = nodes.Test(node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
    736         if negated:
    737             node = nodes.Not(node, lineno=token.lineno)
    738         return node
    739 
    740     def subparse(self, end_tokens = None):
    741         body = []
    742         data_buffer = []
    743         add_data = data_buffer.append
    744         if end_tokens is not None:
    745             self._end_token_stack.append(end_tokens)
    746 
    747         def flush_data():
    748             if data_buffer:
    749                 lineno = data_buffer[0].lineno
    750                 body.append(nodes.Output(data_buffer[:], lineno=lineno))
    751                 del data_buffer[:]
    752 
    753         try:
    754             while self.stream:
    755                 token = self.stream.current
    756                 if token.type == 'data':
    757                     if token.value:
    758                         add_data(nodes.TemplateData(token.value, lineno=token.lineno))
    759                     next(self.stream)
    760                 elif token.type == 'variable_begin':
    761                     next(self.stream)
    762                     add_data(self.parse_tuple(with_condexpr=True))
    763                     self.stream.expect('variable_end')
    764                 elif token.type == 'block_begin':
    765                     flush_data()
    766                     next(self.stream)
    767                     if end_tokens is not None and self.stream.current.test_any(*end_tokens):
    768                         return body
    769                     rv = self.parse_statement()
    770                     if isinstance(rv, list):
    771                         body.extend(rv)
    772                     else:
    773                         body.append(rv)
    774                     self.stream.expect('block_end')
    775                 else:
    776                     raise AssertionError('internal parsing error')
    777 
    778             flush_data()
    779         finally:
    780             if end_tokens is not None:
    781                 self._end_token_stack.pop()
    782 
    783         return body
    784 
    785     def parse(self):
    786         result = nodes.Template(self.subparse(), lineno=1)
    787         result.set_environment(self.environment)
    788         return result