diff options
| author | goodger <goodger@929543f6-e4f2-0310-98a6-ba3bd3dd1d04> | 2002-12-18 01:44:49 +0000 |
|---|---|---|
| committer | goodger <goodger@929543f6-e4f2-0310-98a6-ba3bd3dd1d04> | 2002-12-18 01:44:49 +0000 |
| commit | 173c7a539ca4e2b3a9f8c3a06f67d4a868fd850c (patch) | |
| tree | 436e1eae9f88be159c3640568546b43ee36618b7 /docutils/readers/python | |
| parent | ae5fd4a5e4f398a38b52b712b4a19ad8416139e3 (diff) | |
| download | docutils-173c7a539ca4e2b3a9f8c3a06f67d4a868fd850c.tar.gz | |
More progress; functions done.
git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk/docutils@1027 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
Diffstat (limited to 'docutils/readers/python')
| -rw-r--r-- | docutils/readers/python/moduleparser.py | 197 |
1 files changed, 157 insertions, 40 deletions
diff --git a/docutils/readers/python/moduleparser.py b/docutils/readers/python/moduleparser.py index cbca876a7..8dcf432b2 100644 --- a/docutils/readers/python/moduleparser.py +++ b/docutils/readers/python/moduleparser.py @@ -163,6 +163,14 @@ It's for exactly this reason: ... but it goes past docstring processing. It's also important to keep style decisions and tool-specific data transforms out of this module parser. + +Issues +====== + +* At what point should namespaces be computed? Should they be part of the + basic AST produced by the ASTVisitor walk, or generated by another tree + traversal? + """ __docformat__ = 'reStructuredText' @@ -174,7 +182,7 @@ import tokenize import token from compiler.consts import OP_ASSIGN from compiler.visitor import ASTVisitor -from types import StringType, UnicodeType +from types import StringType, UnicodeType, TupleType def parse_module(module_text, filename): @@ -304,7 +312,13 @@ class AttributeVisitor(BaseVisitor): class FunctionVisitor(DocstringVisitor): + in_function = 0 + def visitFunction(self, node): + if self.in_function: + # Don't bother with nested function definitions. + return + self.in_function = 1 self.function = function = Function(node, node.name) if node.doc is not None: function.append(Docstring(node, node.doc)) @@ -326,11 +340,17 @@ class FunctionVisitor(DocstringVisitor): argnames.pop() defaults = list(node.defaults) defaults = [None] * (len(argnames) - len(defaults)) + defaults + function_parameters = self.token_parser.function_parameters( + node.lineno) + #print >>sys.stderr, function_parameters for argname, default in zip(argnames, defaults): - parameter = Parameter(node, argname) + if type(argname) is TupleType: + parameter = ParameterTuple(node, argname) + argname = normalize_parameter_name(argname) + else: + parameter = Parameter(node, argname) if default: - default_text = self.token_parser.default(node.lineno) - parameter.append(Default(node, default_text)) + parameter.append(Default(node, function_parameters[argname])) parameters.append(parameter) if parameters or special: special.reverse() @@ -463,6 +483,12 @@ class ParameterList(Node): pass class Parameter(Attribute): pass +class ParameterTuple(AttributeTuple): + + def attlist(self): + return Node.attlist(self, names=normalize_parameter_name(self.names)) + + class ExcessPositionalArguments(Parameter): pass @@ -502,47 +528,129 @@ class TokenParser: while self.string != '=': self.next() while self.type != token.NEWLINE and self.string != ';': - append = 1 - append_ws = 1 - del_ws = 0 if self.string == '=': - start_row, start_col = self.end - tokens = [] - last_type = None - last_string = None - backquote = 0 - append = 0 - elif self.string == '.': - del_ws = 1 - append_ws = 0 - elif self.string in ('(', '[', '{'): - append_ws = 0 - if self.string in '([' and (last_type == token.NAME or - last_string in (')', ']', '}')): - del_ws = 1 - elif self.string in (')', ']', '}', ':', ','): - del_ws = 1 - elif self.string == '`': - if backquote: - del_ws = 1 - else: - append_ws = 0 - backquote = not backquote - elif self.type == tokenize.NL: - append = 0 - if append: - if del_ws and tokens and tokens[-1] == ' ': - del tokens[-1] - tokens.append(self.string) - last_type = self.type - last_string = self.string - if append_ws: - tokens.append(' ') + self.tokens = [] + self.stack = [] + self._type = None + self._string = None + self._backquote = 0 + else: + self.note_token() self.next() self.next() - text = ''.join(tokens) + text = ''.join(self.tokens) return text.strip() + openers = {')': '(', ']': '[', '}': '{'} + + def note_token(self): + append = 1 + append_ws = 1 + del_ws = 0 + if self.string == '.': + del_ws = 1 + append_ws = 0 + elif self.string in ('(', '[', '{'): + append_ws = 0 + if self.string in '([' and (self._type == token.NAME or + self._string in (')', ']', '}')): + del_ws = 1 + self.stack.append(self.string) + elif self.string in (')', ']', '}'): + del_ws = 1 + assert self.stack[-1] == self.openers[self.string] + self.stack.pop() + elif self.string in (':', ','): + del_ws = 1 + elif self.string == '`': + if self._backquote: + del_ws = 1 + assert self.stack[-1] == self.string + self.stack.pop() + else: + append_ws = 0 + self.stack.append(self.string) + self._backquote = not self._backquote + elif self.type == tokenize.NL: + append = 0 + if append: + if del_ws and self.tokens and self.tokens[-1] == ' ': + del self.tokens[-1] + self.tokens.append(self.string) + self._type = self.type + self._string = self.string + if append_ws: + self.tokens.append(' ') + + def function_parameters(self, lineno): + """ + Return a dictionary mapping parameters to defaults + (whitespace-normalized strings). + """ + self.goto_line(lineno) + while self.string != 'def': + self.next() + while self.string != '(': + self.next() + name = None + default = None + parameter_tuple = None + self.tokens = [] + parameters = {} + self.stack = [self.string] + self.next() + while 1: + if len(self.stack) == 1: + if parameter_tuple: + # Just encountered ")". + #print >>sys.stderr, 'parameter_tuple: %r' % self.tokens + name = ''.join(self.tokens).strip() + self.tokens = [] + parameter_tuple = None + if self.string in (')', ','): + if name: + if self.tokens: + default_text = ''.join(self.tokens).strip() + else: + default_text = None + parameters[name] = default_text + self.tokens = [] + name = None + default = None + if self.string == ')': + break + elif self.type == token.NAME: + if name and default: + self.note_token() + else: + assert name is None, ( + 'token=%r name=%r parameters=%r stack=%r' + % (self.token, name, parameters, self.stack)) + name = self.string + #print >>sys.stderr, 'name=%r' % name + elif self.string == '=': + assert name is not None, 'token=%r' % (self.token,) + assert default is None, 'token=%r' % (self.token,) + assert self.tokens == [], 'token=%r' % (self.token,) + default = 1 + self._type = None + self._string = None + self._backquote = 0 + elif name: + self.note_token() + elif self.string == '(': + parameter_tuple = 1 + self._type = None + self._string = None + self._backquote = 0 + self.note_token() + else: # ignore these tokens: + assert self.string in ('*', '**', '\n'), ( + 'token=%r' % (self.token,)) + else: + self.note_token() + self.next() + return parameters def trim_docstring(text): """ @@ -573,3 +681,12 @@ def trim_docstring(text): trimmed.pop(0) # Return a single string: return '\n'.join(trimmed) + +def normalize_parameter_name(name): + """ + Converts a tuple like ``('a', ('b', 'c'), 'd')`` into ``'(a, (b, c), d)'`` + """ + if type(name) is TupleType: + return '(%s)' % ', '.join([normalize_parameter_name(n) for n in name]) + else: + return name |
