Partial merge of trunk progress. Some tests still fail.
[cython.git] / Cython / Compiler / Parsing.py
index 4e2c55ad2c2aee350487bbac841dac8b4e0695cc..63ae5c0f16dc33029ce836ac9ee673428cdcf04d 100644 (file)
@@ -22,20 +22,49 @@ from Cython import Utils
 import Future
 import Options
 
+
 class Ctx(object):
-    #  Parsing context
+    """ Parsing context
+
+    * namespace (string): C++ namespace of the source (`None` for C
+      objects, set if the symbol is external)
+    * cdef_flag (boolean): Symbol (data) has a C definition.
+    * c_visibility ('private'|'public'|'extern'|'ignore'):
+
+      * private: Symbol is not accessible to external C code
+      * public: Symbol is accessible to external C code
+      * extern: Symbol is defined elsewhere (otherwise a local
+        definition is created).
+      * ignore: ? something about symbol re-definition?
+
+    * api (boolean): Add to generated header file
+
+
+    * visibility ('private'|'public'|'readonly'):
+
+      * private: Object is not exposed to Python code.
+      * public: Python can read/write to the object's data.
+      * readonly: Python can read (but nut write) the object's data.
+
+    * overridable (boolean): Python references can be overridden in
+      Python (if the object is visible).  This is only supported in
+      class methods.
+    """
     level = 'other'
-    visibility = 'private'
-    cdef_flag = 0
     typedef_flag = 0
-    api = 0
-    overridable = 0
     nogil = 0
-    namespace = None
     templates = None
 
-    def __init__(self, **kwds):
-        self.__dict__.update(kwds)
+    namespace = None
+    cdef_flag = 0
+    c_visibility = 'private'
+    api = 0
+
+    visibility = 'public'
+    overridable = 0
+
+    def __init__(self, **kwargs):
+        self.__dict__.update(kwargs)
 
     def __call__(self, **kwds):
         ctx = Ctx()
@@ -1737,15 +1766,9 @@ 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'):
-            s.error("ctypedef statement not allowed here")
-        #if ctx.api:
-        #    error(s.position(), "'api' not allowed with 'ctypedef'")
-        return p_ctypedef_statement(s, ctx)
-    elif s.sy == 'DEF':
+    pos = s.position()
+    if s.sy == 'DEF':
         return p_DEF_statement(s)
     elif s.sy == 'IF':
         return p_IF_statement(s, ctx)
@@ -1756,66 +1779,94 @@ 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:
+    sy = s.sy
+    ctx = p_binding(s, ctx)
+    if sy == 'ctypedef':
+        if ctx.level not in ('module', 'module_pxd'):
+            s.error("ctypedef statement not allowed here")
+        return p_ctypedef_statement(s, pos, ctx)
+    elif 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))
-        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")
-            node.decorators = decorators
-        return node
-    else:
-        if ctx.api:
+    if ctx.api:
+        if ctx.cdef_flag:
+            if ctx.c_visibility == 'extern':
+                error(pos, "Cannot combine 'api' with 'extern'")
+        else:
             s.error("'api' not allowed with this statement")
-        elif s.sy == 'def':
-            # def statements aren't allowed in pxd files, except
-            # as part of a cdef class
-            if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
-                s.error('def statement not allowed here')
-            s.level = ctx.level
-            return p_def_statement(s, decorators)
-        elif s.sy == 'class':
+    if ctx.cdef_flag and p_nogil(s):
+        ctx.nogil = 1
+        if ctx.overridable:
+            error(pos, "cdef blocks cannot be declared cpdef")
+        return p_cdef_block(s, ctx)
+    elif s.sy == ':' and ctx.cdef_flag:
+        if ctx.overridable:
+            error(pos, "cdef blocks cannot be declared cpdef")
+        return p_cdef_block(s, ctx)
+    elif s.sy == 'def':
+        # def statements aren't allowed in pxd files, except
+        # as part of a cdef class
+        if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
+            s.error('def statement not allowed here')
+        s.level = ctx.level
+        return p_def_statement(s, decorators)
+    elif s.sy == 'class':
+        if ctx.cdef_flag:
+            if ctx.level not in ('module', 'module_pxd'):
+                error(pos, "Extension type definition not allowed here")
+            if ctx.overridable:
+                error(pos, "Extension types cannot be declared cpdef")
+            return p_c_class_definition(s, pos, ctx, decorators)
+        else:
             if ctx.level not in ('module', 'function', 'class', 'other'):
                 s.error("class definition not allowed here")
-            return p_class_statement(s, decorators)
-        elif s.sy == 'include':
+        return p_class_statement(s, decorators)
+    elif s.sy == 'from' and ctx.c_visibility == 'extern':
+        return p_cdef_extern_block(s, pos, ctx)
+    elif s.sy == 'import' and ctx.cdef_flag:
+        s.next()
+        return p_cdef_extern_block(s, pos, ctx)
+    elif s.sy == 'include':
+        if ctx.level not in ('module', 'module_pxd'):
+            s.error("include statement not allowed here")
+        return p_include_statement(s, ctx)
+    elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
+        return p_property_decl(s)
+    elif ctx.cdef_flag:
+        if s.sy == 'IDENT' and s.systring == 'cppclass':
+            if ctx.c_visibility != 'extern':
+                error(pos, "C++ classes need to be declared extern")
+            return p_cpp_class_definition(s, pos, ctx)
+        elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"):
             if ctx.level not in ('module', 'module_pxd'):
-                s.error("include statement not allowed here")
-            return p_include_statement(s, ctx)
-        elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
-            return p_property_decl(s)
-        elif s.sy == 'pass' and ctx.level != 'property':
-            return p_pass_statement(s, with_newline = 1)
-        else:
-            if ctx.level in ('c_class_pxd', 'property'):
-                s.error("Executable statement not allowed here")
-            if s.sy == 'if':
-                return p_if_statement(s)
-            elif s.sy == 'while':
-                return p_while_statement(s)
-            elif s.sy == 'for':
-                return p_for_statement(s)
-            elif s.sy == 'try':
-                return p_try_statement(s)
-            elif s.sy == 'with':
-                return p_with_statement(s)
+                error(pos, "C struct/union/enum definition not allowed here")
+            if ctx.overridable:
+                error(pos, "C struct/union/enum cannot be declared cpdef")
+            if s.systring == "enum":
+                return p_c_enum_definition(s, pos, ctx)
             else:
-                return p_simple_statement_list(
-                    s, ctx, first_statement = first_statement)
+                return p_c_struct_or_union_definition(s, pos, ctx)
+        return p_c_func_or_var_declaration(s, pos, ctx, decorators)
+    elif s.sy == 'pass' and ctx.level != 'property':
+        return p_pass_statement(s, with_newline = 1)
+    elif ctx.level in ('c_class_pxd', 'property'):
+        s.error("Executable statement not allowed here")
+    elif s.sy == 'if':
+        return p_if_statement(s)
+    elif s.sy == 'while':
+        return p_while_statement(s)
+    elif s.sy == 'for':
+        return p_for_statement(s)
+    elif s.sy == 'try':
+        return p_try_statement(s)
+    elif s.sy == 'with':
+        return p_with_statement(s)
+    return p_simple_statement_list(
+        s, ctx, first_statement = first_statement)
 
 def p_statement_list(s, ctx, first_statement = 0):
     # Parse a series of statements separated by newlines.
@@ -1945,7 +1996,6 @@ def p_c_complex_base_type(s):
         base_type = base_type, declarator = declarator)
 
 def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
-    #print "p_c_simple_base_type: self_flag =", self_flag, nonempty
     is_basic = 0
     signed = 1
     longness = 0
@@ -2075,7 +2125,6 @@ def looking_at_expr(s):
         return True
 
 def looking_at_base_type(s):
-    #print "looking_at_base_type?", s.sy, s.systring, s.position()
     return s.sy == 'IDENT' and s.systring in base_type_start_words
 
 def looking_at_dotted_name(s):
@@ -2235,9 +2284,11 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
                 error(s.position(), "Empty declarator")
             name = ""
             cname = None
+        if name == 'Rectangle':
+            pass
         if cname is None and ctx.namespace is not None and nonempty:
             cname = ctx.namespace + "::" + name
-        if name == 'operator' and ctx.visibility == 'extern' and nonempty:
+        if name == 'operator' and ctx.c_visibility == 'extern' and nonempty:
             op = s.sy
             if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
                 s.next()
@@ -2379,49 +2430,6 @@ def p_api(s):
     else:
         return 0
 
-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'):
-            error(pos, "Cannot combine 'api' with '%s'" % ctx.visibility)
-    if (ctx.visibility == 'extern') and s.sy == 'from':
-        return p_cdef_extern_block(s, pos, ctx)
-    elif s.sy == 'import':
-        s.next()
-        return p_cdef_extern_block(s, pos, ctx)
-    elif p_nogil(s):
-        ctx.nogil = 1
-        if ctx.overridable:
-            error(pos, "cdef blocks cannot be declared cpdef")
-        return p_cdef_block(s, ctx)
-    elif s.sy == ':':
-        if ctx.overridable:
-            error(pos, "cdef blocks cannot be declared cpdef")
-        return p_cdef_block(s, ctx)
-    elif s.sy == 'class':
-        if ctx.level not in ('module', 'module_pxd'):
-            error(pos, "Extension type definition not allowed here")
-        if ctx.overridable:
-            error(pos, "Extension types cannot be declared cpdef")
-        return p_c_class_definition(s, pos, ctx)
-    elif s.sy == 'IDENT' and s.systring == 'cppclass':
-        if ctx.visibility != 'extern':
-            error(pos, "C++ classes need to be declared extern")
-        return p_cpp_class_definition(s, pos, ctx)
-    elif s.sy == 'IDENT' and s.systring in ("struct", "union", "enum", "packed"):
-        if ctx.level not in ('module', 'module_pxd'):
-            error(pos, "C struct/union/enum definition not allowed here")
-        if ctx.overridable:
-            error(pos, "C struct/union/enum cannot be declared cpdef")
-        if s.systring == "enum":
-            return p_c_enum_definition(s, pos, ctx)
-        else:
-            return p_c_struct_or_union_definition(s, pos, ctx)
-    else:
-        return p_c_func_or_var_declaration(s, pos, ctx)
-
 def p_cdef_block(s, ctx):
     return p_suite(s, ctx(cdef_flag = 1))
 
@@ -2434,7 +2442,9 @@ def p_cdef_extern_block(s, pos, ctx):
         s.next()
     else:
         include_file = p_string_literal(s, 'u')[2]
-    ctx = ctx(cdef_flag = 1, visibility = 'extern')
+    ctx = ctx()
+    ctx.cdef_flag = 1
+    ctx.c_visibility = 'extern'
     if s.systring == "namespace":
         s.next()
         ctx.namespace = p_string_literal(s, 'u')[2]
@@ -2461,18 +2471,26 @@ def p_c_enum_definition(s, pos, ctx):
     items = None
     s.expect(':')
     items = []
+    # Work around overloading of the 'public' keyword.
+    item_ctx = ctx()
+    if item_ctx.c_visibility in ('public', 'extern'):
+        item_ctx.visibility = 'public'
+    else:
+        item_ctx.c_visibility = 'public'
+        item_ctx.visibility = 'private'
     if s.sy != 'NEWLINE':
-        p_c_enum_line(s, ctx, items)
+        p_c_enum_line(s, item_ctx, items)
     else:
         s.next() # 'NEWLINE'
         s.expect_indent()
         while s.sy not in ('DEDENT', 'EOF'):
-            p_c_enum_line(s, ctx, items)
+            p_c_enum_line(s, item_ctx, items)
         s.expect_dedent()
     return Nodes.CEnumDefNode(
         pos, name = name, cname = cname, items = items,
-        typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
-        api = ctx.api, in_pxd = ctx.level == 'module_pxd')
+        typedef_flag = ctx.typedef_flag, c_visibility = ctx.c_visibility,
+        visibility = ctx.visibility, api = ctx.api,
+        in_pxd = ctx.level == 'module_pxd')
 
 def p_c_enum_line(s, ctx, items):
     if s.sy != 'pass':
@@ -2488,6 +2506,7 @@ def p_c_enum_line(s, ctx, items):
 
 def p_c_enum_item(s, ctx, items):
     pos = s.position()
+    ctx = p_binding(s, ctx)
     name = p_ident(s)
     cname = p_opt_cname(s)
     if cname is None and ctx.namespace is not None:
@@ -2497,7 +2516,10 @@ 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,
+        c_visibility = ctx.c_visibility, visibility = ctx.visibility,
+        in_pxd = ctx.level == 'module_pxd'))
+
 
 def p_c_struct_or_union_definition(s, pos, ctx):
     packed = False
@@ -2519,32 +2541,50 @@ 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_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")
-    return Nodes.CStructOrUnionDefNode(pos,
-        name = name, cname = cname, kind = kind, attributes = attributes,
-        typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
-        api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
+    return Nodes.CStructOrUnionDefNode(pos = pos,
+        name = name,
+        cname = cname,
+        kind = kind,
+        attributes = attributes,
+        typedef_flag = ctx.typedef_flag,
+        cdef_flag = ctx.cdef_flag,
+        overridable = ctx.overridable,
+        c_visibility = ctx.c_visibility,
+        visibility = ctx.visibility,
+        api = ctx.api,
+        in_pxd = ctx.level == 'module_pxd',
+        packed = packed)
 
-def p_visibility(s, prev_visibility):
+def p_visibility(s, ctx):
     pos = s.position()
-    visibility = prev_visibility
     if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
         visibility = s.systring
-        if prev_visibility != 'private' and visibility != prev_visibility:
-            s.error("Conflicting visibility options '%s' and '%s'"
-                % (prev_visibility, visibility))
+        outer_scope = ctx.level in ('module', 'module_pxd')
+        if visibility == 'extern':
+            #if prev_visibility != 'private' and visibility != prev_visibility:
+            #    s.error("Conflicting visibility options '%s' and '%s'"
+            #            % (prev_visibility, visibility))
+            ctx.c_visibility = 'extern'
+            # Need to restore/set default value for Python visibility?
+        elif outer_scope and visibility not in ('readonly',):
+            ctx.c_visibility = visibility
+        else:
+            ctx.visibility = visibility
+            if ctx.visibility != 'private':
+                ctx.c_visibility = 'public'
         s.next()
-    return visibility
+    return ctx
 
 def p_c_modifiers(s):
     if s.sy == 'IDENT' and s.systring in ('inline',):
@@ -2553,7 +2593,26 @@ def p_c_modifiers(s):
         return [modifier] + p_c_modifiers(s)
     return []
 
-def p_c_func_or_var_declaration(s, pos, ctx):
+def p_binding(s, ctx):
+    new_ctx = ctx()
+    new_ctx.overridable = 0
+    if s.sy == 'cdef':
+        new_ctx.cdef_flag = 1
+        s.next()
+    elif s.sy == 'cpdef':
+        new_ctx.cdef_flag = 1
+        new_ctx.overridable = 1
+        s.next()
+    elif s.sy == 'ctypedef':
+        new_ctx.typedef_flag = 1
+        new_ctx.cdef_flag = 1
+        s.next()
+    if new_ctx.cdef_flag:
+        new_ctx = p_visibility(s, new_ctx)
+        new_ctx.api = ctx.api or p_api(s)
+    return new_ctx
+
+def p_c_func_or_var_declaration(s, pos, ctx, decorators=None):
     cmethod_flag = ctx.level in ('c_class', 'c_class_pxd')
     modifiers = p_c_modifiers(s)
     base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates)
@@ -2565,14 +2624,17 @@ def p_c_func_or_var_declaration(s, pos, ctx):
             s.error("C function definition not allowed here")
         doc, suite = p_suite(s, Ctx(level = 'function'), with_doc = 1)
         result = Nodes.CFuncDefNode(pos,
+            cdef_flag = ctx.cdef_flag,
+            overridable = ctx.overridable,
+            c_visibility = ctx.c_visibility,
             visibility = ctx.visibility,
             base_type = base_type,
             declarator = declarator,
+            decorators = decorators,
             body = suite,
             doc = doc,
             modifiers = modifiers,
-            api = ctx.api,
-            overridable = ctx.overridable)
+            api = ctx.api)
     else:
         #if api:
         #    s.error("'api' not allowed with variable declaration")
@@ -2586,23 +2648,17 @@ def p_c_func_or_var_declaration(s, pos, ctx):
             declarators.append(declarator)
         s.expect_newline("Syntax error in C variable declaration")
         result = Nodes.CVarDefNode(pos,
+            c_visibility = ctx.c_visibility,
             visibility = ctx.visibility,
+            api = ctx.api,
+            overridable = ctx.overridable,
             base_type = base_type,
             declarators = declarators,
-            in_pxd = ctx.level == 'module_pxd',
-            api = ctx.api,
-            overridable = ctx.overridable)
+            decorators = decorators,
+            in_pxd = ctx.level == 'module_pxd')
     return result
 
-def p_ctypedef_statement(s, ctx):
-    # s.sy == 'ctypedef'
-    pos = s.position()
-    s.next()
-    visibility = p_visibility(s, ctx.visibility)
-    api = p_api(s)
-    ctx = ctx(typedef_flag = 1, visibility = visibility)
-    if api:
-        ctx.api = 1
+def p_ctypedef_statement(s, pos, ctx):
     if s.sy == 'class':
         return p_c_class_definition(s, pos, ctx)
     elif s.sy == 'IDENT' and s.systring in ('packed', 'struct', 'union', 'enum'):
@@ -2617,10 +2673,9 @@ def p_ctypedef_statement(s, ctx):
         declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1)
         s.expect_newline("Syntax error in ctypedef statement")
         return Nodes.CTypeDefNode(
-            pos, base_type = base_type,
-            declarator = declarator,
-            visibility = visibility, api = api,
-            in_pxd = ctx.level == 'module_pxd')
+            pos, base_type = base_type, declarator = declarator,
+            c_visibility = ctx.c_visibility, visibility = ctx.visibility,
+            api = ctx.api, in_pxd = ctx.level == 'module_pxd')
 
 def p_decorators(s):
     decorators = []
@@ -2714,7 +2769,7 @@ def p_class_statement(s, decorators):
         starstar_arg = starstar_arg,
         doc = doc, body = body, decorators = decorators)
 
-def p_c_class_definition(s, pos,  ctx):
+def p_c_class_definition(s, pos,  ctx, decorators=None):
     # s.sy == 'class'
     s.next()
     module_path = []
@@ -2723,7 +2778,7 @@ def p_c_class_definition(s, pos,  ctx):
         s.next()
         module_path.append(class_name)
         class_name = p_ident(s)
-    if module_path and ctx.visibility != 'extern':
+    if module_path and ctx.c_visibility != 'extern':
         error(pos, "Qualified class name only allowed for 'extern' C class")
     if module_path and s.sy == 'IDENT' and s.systring == 'as':
         s.next()
@@ -2746,7 +2801,7 @@ def p_c_class_definition(s, pos,  ctx):
         base_class_module = ".".join(base_class_path[:-1])
         base_class_name = base_class_path[-1]
     if s.sy == '[':
-        if ctx.visibility not in ('public', 'extern') and not ctx.api:
+        if ctx.c_visibility not in ('public', 'extern') and not ctx.api:
             error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
         objstruct_name, typeobj_name = p_c_class_options(s)
     if s.sy == ':':
@@ -2754,30 +2809,35 @@ def p_c_class_definition(s, pos,  ctx):
             body_level = 'c_class_pxd'
         else:
             body_level = 'c_class'
-        doc, body = p_suite(s, Ctx(level = body_level), with_doc = 1)
+        body_ctx = Ctx(
+            level = body_level,
+            visibility = 'private',
+            c_visibility = 'private')
+        doc, body = p_suite(s, body_ctx, with_doc = 1)
     else:
         s.expect_newline("Syntax error in C class definition")
         doc = None
         body = None
-    if ctx.visibility == 'extern':
+    if ctx.c_visibility == 'extern':
         if not module_path:
             error(pos, "Module name required for 'extern' C class")
         if typeobj_name:
             error(pos, "Type object name specification not allowed for 'extern' C class")
-    elif ctx.visibility == 'public':
+    elif ctx.c_visibility == 'public':
         if not objstruct_name:
             error(pos, "Object struct name specification required for 'public' C class")
         if not typeobj_name:
             error(pos, "Type object name specification required for 'public' C class")
-    elif ctx.visibility == 'private':
+    elif ctx.c_visibility == 'private':
         if ctx.api:
             if not objstruct_name:
                 error(pos, "Object struct name specification required for 'api' C class")
             if not typeobj_name:
                 error(pos, "Type object name specification required for 'api' C class")
     else:
-        error(pos, "Invalid class visibility '%s'" % ctx.visibility)
+        error(pos, "Invalid class visibility '%s'" % ctx.visibility_string())
     return Nodes.CClassDefNode(pos,
+        c_visibility = ctx.c_visibility,
         visibility = ctx.visibility,
         typedef_flag = ctx.typedef_flag,
         api = ctx.api,
@@ -2788,6 +2848,7 @@ def p_c_class_definition(s, pos,  ctx):
         base_class_name = base_class_name,
         objstruct_name = objstruct_name,
         typeobj_name = typeobj_name,
+        decorators = decorators,
         in_pxd = ctx.level == 'module_pxd',
         doc = doc,
         body = body)
@@ -2869,7 +2930,8 @@ def p_module(s, pxd, full_module_name):
     else:
         level = 'module'
 
-    body = p_statement_list(s, Ctx(level = level), first_statement = 1)
+    ctx = Ctx(level = level)
+    body = p_statement_list(s, ctx, first_statement = 1)
     if s.sy != 'EOF':
         s.error("Syntax error in statement [%s,%s]" % (
             repr(s.sy), repr(s.systring)))
@@ -2912,7 +2974,10 @@ def p_cpp_class_definition(s, pos,  ctx):
         s.expect('NEWLINE')
         s.expect_indent()
         attributes = []
-        body_ctx = Ctx(visibility = ctx.visibility)
+        body_ctx = Ctx()
+        #body_ctx = p_visibility(s, body_ctx)
+        body_ctx.c_visibility = ctx.c_visibility
+        body_ctx.visibility = ctx.visibility
         body_ctx.templates = templates
         while s.sy != 'DEDENT':
             if s.systring == 'cppclass':
@@ -2932,6 +2997,7 @@ def p_cpp_class_definition(s, pos,  ctx):
         name = class_name,
         cname = cname,
         base_classes = base_classes,
+        c_visibility = ctx.c_visibility,
         visibility = ctx.visibility,
         in_pxd = ctx.level == 'module_pxd',
         attributes = attributes,
@@ -2977,4 +3043,3 @@ def print_parse_tree(f, node, level, key = None):
             f.write("%s]\n" % ind)
             return
     f.write("%s%s\n" % (ind, node))
-