|
6 | 6 | import tokenize as tk
|
7 | 7 | from itertools import chain, dropwhile
|
8 | 8 | from re import compile as re
|
| 9 | +from .utils import log |
9 | 10 |
|
10 | 11 | try:
|
11 | 12 | from StringIO import StringIO
|
@@ -223,17 +224,26 @@ def __init__(self, message):
|
223 | 224 |
|
224 | 225 |
|
225 | 226 | class TokenStream(object):
|
| 227 | + # A logical newline is where a new expression or statement begins. When |
| 228 | + # there is a physical new line, but not a logical one, for example: |
| 229 | + # (x + |
| 230 | + # y) |
| 231 | + # The token will be tk.NL, not tk.NEWLINE. |
| 232 | + LOGICAL_NEWLINES = {tk.NEWLINE, tk.INDENT, tk.DEDENT} |
| 233 | + |
226 | 234 | def __init__(self, filelike):
|
227 | 235 | self._generator = tk.generate_tokens(filelike.readline)
|
228 | 236 | self.current = Token(*next(self._generator, None))
|
229 | 237 | self.line = self.current.start[0]
|
230 |
| - self.log = logging.getLogger() |
| 238 | + self.log = log |
| 239 | + self.got_logical_newline = True |
231 | 240 |
|
232 | 241 | def move(self):
|
233 | 242 | previous = self.current
|
234 | 243 | current = self._next_from_generator()
|
235 | 244 | self.current = None if current is None else Token(*current)
|
236 | 245 | self.line = self.current.start[0] if self.current else self.line
|
| 246 | + self.got_logical_newline = (previous.kind in self.LOGICAL_NEWLINES) |
237 | 247 | return previous
|
238 | 248 |
|
239 | 249 | def _next_from_generator(self):
|
@@ -270,8 +280,7 @@ class Parser(object):
|
270 | 280 |
|
271 | 281 | def parse(self, filelike, filename):
|
272 | 282 | """Parse the given file-like object and return its Module object."""
|
273 |
| - # TODO: fix log |
274 |
| - self.log = logging.getLogger() |
| 283 | + self.log = log |
275 | 284 | self.source = filelike.readlines()
|
276 | 285 | src = ''.join(self.source)
|
277 | 286 | try:
|
@@ -336,6 +345,8 @@ def parse_decorators(self):
|
336 | 345 | at_arguments = False
|
337 | 346 |
|
338 | 347 | while self.current is not None:
|
| 348 | + self.log.debug("parsing decorators, current token is %r (%s)", |
| 349 | + self.current.kind, self.current.value) |
339 | 350 | if (self.current.kind == tk.NAME and
|
340 | 351 | self.current.value in ['def', 'class']):
|
341 | 352 | # Done with decorators - found function or class proper
|
@@ -373,9 +384,12 @@ def parse_definitions(self, class_, all=False):
|
373 | 384 | while self.current is not None:
|
374 | 385 | self.log.debug("parsing definition list, current token is %r (%s)",
|
375 | 386 | self.current.kind, self.current.value)
|
| 387 | + self.log.debug('got_newline: %s', self.stream.got_logical_newline) |
376 | 388 | if all and self.current.value == '__all__':
|
377 | 389 | self.parse_all()
|
378 |
| - elif self.current.kind == tk.OP and self.current.value == '@': |
| 390 | + elif (self.current.kind == tk.OP and |
| 391 | + self.current.value == '@' and |
| 392 | + self.stream.got_logical_newline): |
379 | 393 | self.consume(tk.OP)
|
380 | 394 | self.parse_decorators()
|
381 | 395 | elif self.current.value in ['def', 'class']:
|
@@ -471,6 +485,7 @@ def parse_definition(self, class_):
|
471 | 485 | assert self.current.kind != tk.INDENT
|
472 | 486 | docstring = self.parse_docstring()
|
473 | 487 | decorators = self._accumulated_decorators
|
| 488 | + self.log.debug("current accumulated decorators: %s", decorators) |
474 | 489 | self._accumulated_decorators = []
|
475 | 490 | self.log.debug("parsing nested definitions.")
|
476 | 491 | children = list(self.parse_definitions(class_))
|
|
0 commit comments