def parse_mul(self): left = self.parse_div() while self.stream.current.type == 'mul': next(self.stream) right = self.parse_div() left = nodes.Mul(left, right) return left
def parse_floordiv(self): left = self.parse_mod() while self.stream.current.type == 'floordiv': next(self.stream) right = self.parse_mod() left = nodes.FloorDiv(left, right) return left
def parse_mod(self): left = self.parse_pow() while self.stream.current.type == 'mod': next(self.stream) right = self.parse_pow() left = nodes.Mod(left, right) return left
def parse_pow(self): left = self.parse_unary() while self.stream.current.type == 'pow': next(self.stream) right = self.parse_unary() left = nodes.Pow(left, right) return left
def parse_test(self, node): token = next(self.stream) if self.stream.current.test('name:not'): next(self.stream) negated = True else: negated = False name = self.stream.expect('name').value while self.stream.current.type == 'dot': next(self.stream) name += '.' + self.stream.expect('name').value dyn_args = dyn_kwargs = None kwargs = [] if self.stream.current.type == 'lparen': args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) 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'): if self.stream.current.test('name:is'): self.fail('You cannot chain multiple tests with is') args = [self.parse_expression()] else: args = [] node = nodes.Test(node, name, args, kwargs, dyn_args, dyn_kwargs) if negated: node = nodes.Not(node) return node
def parse_sub(self): left = self.parse_concat() while self.stream.current.type == 'sub': next(self.stream) right = self.parse_concat() left = nodes.Sub(left, right) return left
def parse_add(self): left = self.parse_sub() while self.stream.current.type == 'add': next(self.stream) right = self.parse_sub() left = nodes.Add(left, right) return left
def parse_compare(self): expr = self.parse_add() ops = [] while 1: token_type = self.stream.current.type if token_type == 'assign': token_type = 'eq' warnings.warn( "Operator '=' is deprecated and will be removed in Django 1.10. " "Use '==' instead.", DjangoDeprecationWarning, stacklevel=2) if token_type in _compare_operators: next(self.stream) ops.append(nodes.Operand(token_type, self.parse_add())) elif self.stream.skip_if('name:in'): ops.append(nodes.Operand('in', self.parse_add())) elif self.stream.current.test('name:not') and \ self.stream.look().test('name:in'): self.stream.skip(2) ops.append(nodes.Operand('notin', self.parse_add())) else: break if not ops: return expr return nodes.Compare(expr, ops)
def __next__(self): token = self.stream.current if token.type is TOKEN_EOF: self.stream.close() raise StopIteration() next(self.stream) return token
def parse_concat(self): args = [self.parse_mul()] while self.stream.current.type == 'tilde': next(self.stream) args.append(self.parse_mul()) if len(args) == 1: return args[0] return nodes.Concat(args)
def expect(self, expr): """Expect a given token type and return it. This accepts the same argument as :meth:`blended_tags.lexer.Token.test`. """ if not self.current.test(expr): expr = describe_token_expr(expr) raise UnexpectedTokenError(expr, describe_token(self.current)) try: return self.current finally: next(self)
def parse_primary(self): token = self.stream.current if token.type == 'name': if token.value in ('true', 'false', 'True', 'False'): node = nodes.Const(token.value in ('true', 'True')) elif token.value in ('none', 'None'): node = nodes.Const(None) else: node = nodes.Name(token.value) next(self.stream) elif token.type == 'string': next(self.stream) node = nodes.Const(token.value) elif token.type in ('integer', 'float'): next(self.stream) node = nodes.Const(token.value) elif token.type == 'lparen': next(self.stream) node = self.parse_tuple(explicit_parentheses=True) self.stream.expect('rparen') elif token.type == 'lbracket': node = self.parse_list() elif token.type == 'lbrace': node = self.parse_dict() else: self.fail("unexpected '%s'" % describe_token(token)) return node
def parse_unary(self, with_filter=True): token_type = self.stream.current.type if token_type == 'sub': next(self.stream) node = nodes.Neg(self.parse_unary(False)) elif token_type == 'add': next(self.stream) node = nodes.Pos(self.parse_unary(False)) else: node = self.parse_primary() node = self.parse_postfix(node) if with_filter: node = self.parse_filter_expr(node) return node
def parse_call(self, node): token = self.stream.expect('lparen') args = [] kwargs = [] dyn_args = dyn_kwargs = None require_comma = False def ensure(expr): if not expr: self.fail('invalid syntax for function call expression', token.lineno) while self.stream.current.type != 'rparen': if require_comma: self.stream.expect('comma') # support for trailing comma if self.stream.current.type == 'rparen': break if self.stream.current.type == 'mul': ensure(dyn_args is None and dyn_kwargs is None) next(self.stream) dyn_args = self.parse_expression() elif self.stream.current.type == 'pow': ensure(dyn_kwargs is None) next(self.stream) dyn_kwargs = self.parse_expression() else: ensure(dyn_args is None and dyn_kwargs is None) if self.stream.current.type == 'name' and \ self.stream.look().type == 'assign': key = self.stream.current.value self.stream.skip(2) value = self.parse_expression() kwargs.append(nodes.Keyword(key, value)) else: ensure(not kwargs) args.append(self.parse_expression()) require_comma = True self.stream.expect('rparen') if node is None: return args, kwargs, dyn_args, dyn_kwargs return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs)
def parse_subscribed(self): if self.stream.current.type == 'colon': next(self.stream) args = [None] else: node = self.parse_expression() if self.stream.current.type != 'colon': return node next(self.stream) args = [node] if self.stream.current.type == 'colon': args.append(None) elif self.stream.current.type not in ('rbracket', 'comma'): args.append(self.parse_expression()) else: args.append(None) if self.stream.current.type == 'colon': next(self.stream) if self.stream.current.type not in ('rbracket', 'comma'): args.append(self.parse_expression()) else: args.append(None) else: args.append(None) return nodes.Slice(*args)
def parse_filter(self, node, start_inline=False): while self.stream.current.type == 'pipe' or start_inline: if not start_inline: next(self.stream) token = self.stream.expect('name') name = token.value while self.stream.current.type == 'dot': next(self.stream) name += '.' + self.stream.expect('name').value if self.stream.current.type == 'lparen': args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None) elif self.stream.current.type == 'colon': next(self.stream) # this can't just be parsed as an expression because there would # be ambiguity with regards to the application of filters down the chain args = [self.parse_unary(with_filter=False)] kwargs = [] dyn_args = dyn_kwargs = None else: args = [] kwargs = [] dyn_args = dyn_kwargs = None filter_func = self.django_parser.find_filter(name) node = nodes.Filter(node, filter_func, name, args, kwargs, dyn_args, dyn_kwargs) start_inline = False return node
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) elif attr_token.type != 'integer': self.fail('expected name or number', attr_token.lineno) arg = nodes.Const(attr_token.value) return nodes.Getitem(node, arg) 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) return nodes.Getitem(node, arg) self.fail('expected subscript expression', self.lineno)
def skip(self, n=1): """Got n tokens ahead.""" for x in range(n): next(self)
def next_if(self, expr): """Perform the token test and return the token if it matched. Otherwise the return value is `None`. """ if self.current.test(expr): return next(self)
def parse_not(self): if self.stream.current.test('name:not'): next(self.stream) return nodes.Not(self.parse_not()) return self.parse_compare()
def look(self): """Look at the next token.""" old_token = next(self) result = self.current self.push(old_token) return result