implement 'allow_none_for_extension_args' directive for 'not None' and 'or None'...
authorStefan Behnel <scoder@users.berlios.de>
Wed, 14 Apr 2010 14:52:42 +0000 (16:52 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Wed, 14 Apr 2010 14:52:42 +0000 (16:52 +0200)
Cython/Compiler/Nodes.py
Cython/Compiler/Options.py
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py

index bf4880d82a60b64b6fbb97330b8af56a30de8c3b..bad8e955e0dd90f9991e2ad8d1d2ba1c7a8b300b 100644 (file)
@@ -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)))
index 5f32abddff63dd20b9480a8f781cb1c31f0a65e7..6e3d8958a020a94f28b6a273a6470ce4c9b2f601 100644 (file)
@@ -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' : "",
index 7287dd51ca1bc0d51352859d0e104b568254cec0..5966cc426180c1f37529c8d6406e298ce41ec4e7 100644 (file)
@@ -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)
 
index ba0f991a1e4ab30634e8592b9c7edba6dd99a7ed..d2603bdfb870202240e923a3dc97c925b1190e80 100755 (executable)
@@ -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):