Parse Python bindings for structs, enums, and unions.
authorW. Trevor King <wking@drexel.edu>
Sat, 19 Feb 2011 19:45:35 +0000 (14:45 -0500)
committerW. Trevor King <wking@drexel.edu>
Sat, 19 Feb 2011 19:45:38 +0000 (14:45 -0500)
Add p_c_python_binding to Cython.Compiler.Parsing and use it to parse
Python bindings of the form

    [cdef|cpdef] <visibility>

where <visibility> is only checked if the cdef flag is set.

In some places (e.g. stucts, enums, unions, and their members) this
syntax is new.  For classes and their members, p_c_python_binding
mimics the previous implementation.  Where the syntax is new, the
supporting Node changes have not yet been implemented.

The test suite currently passes with the exception of position
specifications for some error messages.  I'm waiting for feedback from
the mailing list to see how these should be addressed.

Cython/Compiler/Parsing.pxd
Cython/Compiler/Parsing.py
Cython/Compiler/Symtab.py

index 3c64665261e6402ea5e5fe5cbb0c2cbd2288d042..425bb5e3ebf4593ef5cbdf99f3716baa3657d7ea 100644 (file)
@@ -160,6 +160,7 @@ cdef p_c_enum_item(PyrexScanner s, ctx, list items)
 cdef p_c_struct_or_union_definition(PyrexScanner s, pos, ctx)
 cdef p_visibility(PyrexScanner s, prev_visibility)
 cdef p_c_modifiers(PyrexScanner s)
+cdef p_c_python_binding(PyrexScanner s, ctx)
 cdef p_c_func_or_var_declaration(PyrexScanner s, pos, ctx)
 cdef p_ctypedef_statement(PyrexScanner s, ctx)
 cdef p_decorators(PyrexScanner s)
index 2cd437e771a4a624b2275392e6aefa3c2c87701d..b8e548353a24c24d459b5078a2ae311d76388a0b 100644 (file)
@@ -1690,7 +1690,6 @@ def p_IF_statement(s, ctx):
     return result
 
 def p_statement(s, ctx, first_statement = 0):
-    cdef_flag = ctx.cdef_flag
     decorators = None
     if s.sy == 'ctypedef':
         if ctx.level not in ('module', 'module_pxd'):
@@ -1709,23 +1708,15 @@ def p_statement(s, ctx, first_statement = 0):
         decorators = p_decorators(s)
         if s.sy not in ('def', 'cdef', 'cpdef', 'class'):
             s.error("Decorators can only be followed by functions or classes")
-    elif s.sy == 'pass' and cdef_flag:
+    elif s.sy == 'pass' and ctx.cdef_flag:
         # empty cdef block
         return p_pass_statement(s, with_newline = 1)
-
-    overridable = 0
-    if s.sy == 'cdef':
-        cdef_flag = 1
-        s.next()
-    elif s.sy == 'cpdef':
-        cdef_flag = 1
-        overridable = 1
-        s.next()
-    if cdef_flag:
+    ctx = p_c_python_binding(s, ctx)
+    if ctx.cdef_flag:
         if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
             s.error('cdef statement not allowed here')
         s.level = ctx.level
-        node = p_cdef_statement(s, ctx(overridable = overridable))
+        node = p_cdef_statement(s, ctx)
         if decorators is not None:
             if not isinstance(node, (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)):
                 s.error("Decorators can only be followed by functions or classes")
@@ -2329,7 +2320,6 @@ def p_api(s):
 
 def p_cdef_statement(s, ctx):
     pos = s.position()
-    ctx.visibility = p_visibility(s, ctx.visibility)
     ctx.api = ctx.api or p_api(s)
     if ctx.api:
         if ctx.visibility not in ('private', 'public'):
@@ -2436,6 +2426,7 @@ def p_c_enum_line(s, ctx, items):
 
 def p_c_enum_item(s, ctx, items):
     pos = s.position()
+    ctx = p_c_python_binding(s, ctx)
     name = p_ident(s)
     cname = p_opt_cname(s)
     if cname is None and ctx.namespace is not None:
@@ -2445,7 +2436,9 @@ def p_c_enum_item(s, ctx, items):
         s.next()
         value = p_test(s)
     items.append(Nodes.CEnumDefItemNode(pos,
-        name = name, cname = cname, value = value))
+        name = name, cname = cname, value = value,
+        visibility = ctx.visibility,
+        in_pxd = ctx.level == 'module_pxd'))
 
 def p_c_struct_or_union_definition(s, pos, ctx):
     packed = False
@@ -2467,14 +2460,14 @@ def p_c_struct_or_union_definition(s, pos, ctx):
         s.expect('NEWLINE')
         s.expect_indent()
         attributes = []
-        body_ctx = Ctx()
         while s.sy != 'DEDENT':
-            if s.sy != 'pass':
-                attributes.append(
-                    p_c_func_or_var_declaration(s, s.position(), body_ctx))
-            else:
+            if s.sy == 'pass':
                 s.next()
                 s.expect_newline("Expected a newline")
+            else:
+                body_ctx = p_c_python_binding(s, Ctx())
+                attributes.append(
+                    p_c_func_or_var_declaration(s, s.position(), body_ctx))
         s.expect_dedent()
     else:
         s.expect_newline("Syntax error in struct or union definition")
@@ -2501,6 +2494,25 @@ def p_c_modifiers(s):
         return [modifier] + p_c_modifiers(s)
     return []
 
+def p_c_python_binding(s, ctx):
+    cdef_flag = ctx.cdef_flag
+    overridable = ctx
+    cdef_flag = ctx.cdef_flag
+    overridable = 0
+    if s.sy == 'cdef':
+        cdef_flag = 1
+        s.next()
+    elif s.sy == 'cpdef':
+        cdef_flag = 1
+        overridable = 1
+        s.next()
+    if cdef_flag:
+        visibility = p_visibility(s, ctx.visibility)
+    else:
+        visibility = ctx.visibility
+    return ctx(
+        cdef_flag=cdef_flag, overridable=overridable, visibility=visibility)
+
 def p_c_func_or_var_declaration(s, pos, ctx):
     cmethod_flag = ctx.level in ('c_class', 'c_class_pxd')
     modifiers = p_c_modifiers(s)
@@ -2856,7 +2868,7 @@ def p_cpp_class_definition(s, pos,  ctx):
         s.expect('NEWLINE')
         s.expect_indent()
         attributes = []
-        body_ctx = Ctx(visibility = ctx.visibility)
+        body_ctx = Ctx(visibility = p_visibility(s, ctx.visibility))
         body_ctx.templates = templates
         while s.sy != 'DEDENT':
             if s.systring == 'cppclass':
index 74a80eb834111c1cae2cf1af1d3c47cf95a03351..a032ce8b810b0f284f7e17198b475c26518f47cf 100644 (file)
@@ -1409,9 +1409,6 @@ class StructOrUnionScope(Scope):
         if type.is_pyobject and not allow_pyobject:
             error(pos,
                   "C struct/union member cannot be a Python object")
-        if visibility != 'private':
-            error(pos,
-                  "C struct/union member cannot be declared %s" % visibility)
         return entry
 
     def declare_cfunction(self, name, type, pos,