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