From 765f2b7a2e62ff352df5ec8a6c2a4cb92c4120e0 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Sat, 30 Oct 2010 15:24:04 +0200 Subject: [PATCH] clean up directive decorator parsing, support boolean directives as plain names, support directives on cdef classes --- Cython/Compiler/ParseTreeTransforms.py | 116 +++++++++++++++---------- 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 9e169247..3e6a398b 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -727,7 +727,18 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): return directives directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos)) return directives - + elif isinstance(node, (AttributeNode, NameNode)): + self.visit(node) + optname = node.as_cython_attribute() + if optname: + directivetype = Options.directive_types.get(optname) + if directivetype is bool: + return [(optname, True)] + elif directivetype is None: + return [(optname, None)] + else: + raise PostParseError( + node.pos, "The '%s' directive should be used as a function call." % optname) return None def try_to_parse_directive(self, optname, args, kwds, pos): @@ -771,57 +782,66 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): # Handle decorators def visit_FuncDefNode(self, node): - directives = [] - if node.decorators: - # Split the decorators into two lists -- real decorators and directives - realdecs = [] - for dec in node.decorators: - new_directives = self.try_to_parse_directives(dec.decorator) - if new_directives is not None: - directives.extend(new_directives) + directives = self._extract_directives(node, 'function') + if not directives: + return self.visit_Node(node) + body = StatListNode(node.pos, stats=[node]) + return self.visit_with_directives(body, directives) + + def visit_CVarDefNode(self, node): + for dec in node.decorators: + for directive in self.try_to_parse_directives(dec.decorator) or (): + if directive is not None and directive[0] == u'locals': + node.directive_locals = directive[1] else: - realdecs.append(dec) - if realdecs and isinstance(node, CFuncDefNode): - raise PostParseError(realdecs[0].pos, "Cdef functions cannot take arbitrary decorators.") + self.context.nonfatal_error(PostParseError(dec.pos, + "Cdef functions can only take cython.locals() decorator.")) + return node + + def visit_CClassDefNode(self, node): + directives = self._extract_directives(node, 'cclass') + if not directives: + return self.visit_Node(node) + body = StatListNode(node.pos, stats=[node]) + return self.visit_with_directives(body, directives) + + def _extract_directives(self, node, scope_name): + if not node.decorators: + return {} + # Split the decorators into two lists -- real decorators and directives + directives = [] + realdecs = [] + for dec in node.decorators: + new_directives = self.try_to_parse_directives(dec.decorator) + if new_directives is not None: + for directive in new_directives: + if self.check_directive_scope(node.pos, directive[0], scope_name): + directives.append(directive) else: - node.decorators = realdecs - - if directives: - optdict = {} - directives.reverse() # Decorators coming first take precedence - for directive in directives: - name, value = directive - legal_scopes = Options.directive_scopes.get(name, None) - if not self.check_directive_scope(node.pos, name, 'function'): - continue - if name in optdict: - old_value = optdict[name] - # keywords and arg lists can be merged, everything - # else overrides completely - if isinstance(old_value, dict): - old_value.update(value) - elif isinstance(old_value, list): - old_value.extend(value) - else: - optdict[name] = value + realdecs.append(dec) + if realdecs and isinstance(node, (CFuncDefNode, CClassDefNode)): + raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.") + else: + node.decorators = realdecs + # merge or override repeated directives + optdict = {} + directives.reverse() # Decorators coming first take precedence + for directive in directives: + name, value = directive + if name in optdict: + old_value = optdict[name] + # keywords and arg lists can be merged, everything + # else overrides completely + if isinstance(old_value, dict): + old_value.update(value) + elif isinstance(old_value, list): + old_value.extend(value) else: optdict[name] = value - body = StatListNode(node.pos, stats=[node]) - return self.visit_with_directives(body, optdict) - else: - return self.visit_Node(node) - - def visit_CVarDefNode(self, node): - if node.decorators: - for dec in node.decorators: - for directive in self.try_to_parse_directives(dec.decorator) or []: - if directive is not None and directive[0] == u'locals': - node.directive_locals = directive[1] - else: - self.context.nonfatal_error(PostParseError(dec.pos, - "Cdef functions can only take cython.locals() decorator.")) - return node - + else: + optdict[name] = value + return optdict + # Handle with statements def visit_WithStatNode(self, node): directive_dict = {} -- 2.26.2