From 7c016d54326642ec4cc4b385b1340f77bccf7667 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 14 Apr 2010 16:52:42 +0200 Subject: [PATCH] implement 'allow_none_for_extension_args' directive for 'not None' and 'or None' arg anntation --- Cython/Compiler/Nodes.py | 23 ++++++++++++++++++----- Cython/Compiler/Options.py | 1 + Cython/Compiler/Parsing.py | 11 +++++++---- Cython/Compiler/PyrexTypes.py | 8 ++++++-- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index bf4880d8..bad8e955 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -630,6 +630,8 @@ class CArgDeclNode(Node): # base_type CBaseTypeNode # declarator CDeclaratorNode # not_none boolean Tagged with 'not None' + # or_none boolean Tagged with 'or None' + # accept_none boolean Resolved boolean for not_none/or_none # default ExprNode or None # default_value PyObjectConst constant for default value # is_self_arg boolean Is the "self" arg of an extension type method @@ -1658,7 +1660,7 @@ class CFuncDefNode(FuncDefNode): 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % ( arg_code, typeptr_cname, - not arg.not_none, + arg.accept_none, arg.name, type.is_builtin_type, code.error_goto(arg.pos))) @@ -1849,6 +1851,7 @@ class DefNode(FuncDefNode): def analyse_argument_types(self, env): directive_locals = self.directive_locals = env.directives['locals'] + allow_none_for_extension_args = env.directives['allow_none_for_extension_args'] for arg in self.args: if hasattr(arg, 'name'): type = arg.type @@ -1877,9 +1880,19 @@ class DefNode(FuncDefNode): arg.needs_conversion = 0 arg.needs_type_test = 0 arg.is_generic = 1 - if arg.not_none and not arg.type.is_extension_type: - error(self.pos, - "Only extension type arguments can have 'not None'") + if arg.type.is_extension_type: + if arg.or_none: + arg.accept_none = True + elif arg.not_none: + arg.accept_none = False + else: + # default depends on compiler directive + arg.accept_none = allow_none_for_extension_args + else: + if arg.not_none: + error(self.pos, "Only extension type arguments can have 'not None'") + if arg.or_none: + error(self.pos, "Only extension type arguments can have 'or None'") def analyse_signature(self, env): any_type_tests_needed = 0 @@ -2650,7 +2663,7 @@ class DefNode(FuncDefNode): 'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % ( arg_code, typeptr_cname, - not arg.not_none, + arg.accept_none, arg.name, arg.type.is_builtin_type, code.error_goto(arg.pos))) diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 5f32abdd..6e3d8958 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -58,6 +58,7 @@ directive_defaults = { 'cdivision': False, # was True before 0.12 'cdivision_warnings': False, 'always_allow_keywords': False, + 'allow_none_for_extension_args': True, 'wraparound' : True, 'ccomplex' : False, # use C99/C++ for complex types and arith 'callspec' : "", diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 7287dd51..5966cc42 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -2081,7 +2081,7 @@ def p_optional_ellipsis(s): def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0): pos = s.position() - not_none = 0 + not_none = or_none = 0 default = None if s.in_python_file: # empty type declaration @@ -2093,15 +2093,17 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0) else: base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty) declarator = p_c_declarator(s, ctx, nonempty = nonempty) - if s.sy == 'not' and not s.in_python_file: + if s.sy in ('not', 'or') and not s.in_python_file: + kind = s.sy s.next() if s.sy == 'IDENT' and s.systring == 'None': s.next() else: s.error("Expected 'None'") if not in_pyfunc: - error(pos, "'not None' only allowed in Python functions") - not_none = 1 + error(pos, "'%s None' only allowed in Python functions" % kind) + or_none = kind == 'or' + not_none = kind == 'not' if s.sy == '=': s.next() if 'pxd' in s.level: @@ -2115,6 +2117,7 @@ def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0) base_type = base_type, declarator = declarator, not_none = not_none, + or_none = or_none, default = default, kw_only = kw_only) diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index ba0f991a..d2603bdf 100755 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -1638,7 +1638,12 @@ class CFuncTypeArg(object): # cname string # type PyrexType # pos source file position - + + # FIXME: is this the right setup? should None be allowed here? + not_none = False + or_none = False + accept_none = True + def __init__(self, name, type, pos, cname=None): self.name = name if cname is not None: @@ -1647,7 +1652,6 @@ class CFuncTypeArg(object): self.cname = Naming.var_prefix + name self.type = type self.pos = pos - self.not_none = False self.needs_type_test = False # TODO: should these defaults be set in analyse_types()? def __repr__(self): -- 2.26.2