From: W. Trevor King Date: Sat, 19 Feb 2011 19:45:35 +0000 (-0500) Subject: Parse Python bindings for structs, enums, and unions. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=76be7f14f7a753e103f9632120a5076fc3b0221f;p=cython.git Parse Python bindings for structs, enums, and unions. Add p_c_python_binding to Cython.Compiler.Parsing and use it to parse Python bindings of the form [cdef|cpdef] where 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. --- diff --git a/Cython/Compiler/Parsing.pxd b/Cython/Compiler/Parsing.pxd index 3c646652..425bb5e3 100644 --- a/Cython/Compiler/Parsing.pxd +++ b/Cython/Compiler/Parsing.pxd @@ -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) diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 2cd437e7..b8e54835 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -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': diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 74a80eb8..a032ce8b 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -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,