From: Dag Sverre Seljebotn Date: Thu, 1 Oct 2009 09:35:14 +0000 (+0200) Subject: Functionality for only allowing directives in certain areas X-Git-Tag: 0.12.alpha0~186^2~3 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=d12a8228bd46be125aa108f97b2b80a9ad51cea0;p=cython.git Functionality for only allowing directives in certain areas --- diff --git a/Cython/Compiler/DebugFlags.py b/Cython/Compiler/DebugFlags.py index d6d52189..f7f5a0eb 100644 --- a/Cython/Compiler/DebugFlags.py +++ b/Cython/Compiler/DebugFlags.py @@ -10,7 +10,7 @@ debug_temp_code_comments = 0 debug_trace_code_generation = 0 # Do not replace exceptions with user-friendly error messages -debug_no_exception_intercept = 0 +debug_no_exception_intercept = 1 # Print a message each time a new stage in the pipeline is entered debug_verbose_pipeline = 0 diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 68eb6966..0739f249 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -68,6 +68,7 @@ option_defaults = { 'c99_complex' : False, # Don't use macro wrappers for complex arith, not sure what to name this... 'callspec' : "", 'profile': False, + 'doctesthack': False } # Override types possibilities above, if needed @@ -77,6 +78,11 @@ for key, val in option_defaults.items(): if key not in option_types: option_types[key] = type(val) +option_scopes = { # defaults to available everywhere + # 'module', 'function', 'class', 'with statement' + 'doctesthack' : ('module',) +} + def parse_option_value(name, value): """ Parses value as an option value for the given name and returns diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 5dad3786..13142396 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -338,14 +338,26 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): self.cython_module_names = set() self.option_names = {} + def check_directive_scope(self, pos, directive, scope): + legal_scopes = Options.option_scopes.get(directive, None) + if legal_scopes and scope not in legal_scopes: + self.context.nonfatal_error(PostParseError(pos, 'The %s compiler directive ' + 'is not allowed in %s scope' % (directive, scope))) + return False + else: + return True + # Set up processing and handle the cython: comments. def visit_ModuleNode(self, node): options = copy.copy(Options.option_defaults) for key, value in self.compilation_option_overrides.iteritems(): + if not self.check_directive_scope(node.pos, key, 'module'): + self.wrong_scope_error(node.pos, key, 'module') + del self.compilation_option_overrides[key] + continue if key in node.option_comments and node.option_comments[key] != value: warning(node.pos, "Compiler directive differs between environment and file header; this will change " "in Cython 0.12. See http://article.gmane.org/gmane.comp.python.cython.devel/5233", 2) - break options.update(node.option_comments) options.update(self.compilation_option_overrides) self.options = options @@ -465,7 +477,6 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): # Handle decorators def visit_FuncDefNode(self, node): options = [] - if node.decorators: # Split the decorators into two lists -- real decorators and options realdecs = [] @@ -485,6 +496,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): options.reverse() # Decorators coming first take precedence for option in options: name, value = option + legal_scopes = Options.option_scopes.get(name, None) + if not self.check_directive_scope(node.pos, name, 'function'): + continue if name in optdict and isinstance(optdict[name], dict): # only keywords can be merged, everything else # overrides completely @@ -503,7 +517,9 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): if option is not None and option[0] == u'locals': node.directive_locals = option[1] else: - raise PostParseError(dec.pos, "Cdef functions can only take cython.locals() decorator.") + self.context.nonfatal_error(PostParseError(dec.pos, + "Cdef functions can only take cython.locals() decorator.")) + continue return node # Handle with statements @@ -511,11 +527,13 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): option = self.try_to_parse_option(node.manager) if option is not None: if node.target is not None: - raise PostParseError(node.pos, "Compiler option with statements cannot contain 'as'") - name, value = option - return self.visit_with_options(node.body, {name:value}) - else: - return self.visit_Node(node) + self.context.nonfatal_error( + PostParseError(node.pos, "Compiler option with statements cannot contain 'as'")) + else: + name, value = option + if self.check_directive_scope(node.pos, name, 'with statement'): + return self.visit_with_options(node.body, {name:value}) + return self.visit_Node(node) class WithTransform(CythonTransform, SkipDeclarations): diff --git a/tests/errors/e_doctesthack.pyx b/tests/errors/e_doctesthack.pyx new file mode 100644 index 00000000..56c4df05 --- /dev/null +++ b/tests/errors/e_doctesthack.pyx @@ -0,0 +1,9 @@ +cimport cython + +@cython.doctesthack(False) +def foo(): + pass + +_ERRORS = u""" +4:0: The doctesthack compiler directive is not allowed in function scope +"""