Commit 765f2b7a authored by Stefan Behnel's avatar Stefan Behnel

clean up directive decorator parsing, support boolean directives as plain...

clean up directive decorator parsing, support boolean directives as plain names, support directives on cdef classes
parent 0722bb26
......@@ -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,29 +782,52 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
# Handle decorators
def visit_FuncDefNode(self, node):
directives = []
if node.decorators:
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:
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:
directives.extend(new_directives)
for directive in new_directives:
if self.check_directive_scope(node.pos, directive[0], scope_name):
directives.append(directive)
else:
realdecs.append(dec)
if realdecs and isinstance(node, CFuncDefNode):
raise PostParseError(realdecs[0].pos, "Cdef functions cannot take arbitrary decorators.")
if realdecs and isinstance(node, (CFuncDefNode, CClassDefNode)):
raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.")
else:
node.decorators = realdecs
if directives:
# merge or override repeated 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
......@@ -806,21 +840,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
optdict[name] = 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
return optdict
# Handle with statements
def visit_WithStatNode(self, node):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment