# in_pxd boolean
# api boolean
# need_properties [entry]
- # pxd_locals [CVarDefNode] (used for functions declared in pxd)
+
+ # directive_locals { string : NameNode } locals defined by cython.locals(...)
child_attrs = ["base_type", "declarators"]
need_properties = ()
- pxd_locals = []
+ directive_locals = {}
def analyse_declarations(self, env, dest_scope = None):
if not dest_scope:
cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
api = self.api)
if entry is not None:
- entry.pxd_locals = self.pxd_locals
+ entry.directive_locals = self.directive_locals
else:
+ if self.directive_locals:
+ s.error("Decorators can only be followed by functions")
if self.in_pxd and self.visibility != 'extern':
error(self.pos,
"Only 'extern' C variable declaration allowed in .pxd file")
# #filename string C name of filename string const
# entry Symtab.Entry
# needs_closure boolean Whether or not this function has inner functions/classes/yield
- # pxd_locals [CVarDefNode] locals defined in the pxd
+ # directive_locals { string : NameNode } locals defined by cython.locals(...)
py_func = None
assmt = None
needs_closure = False
- pxd_locals = []
def analyse_default_values(self, env):
genv = env.global_scope()
# declarator CDeclaratorNode
# body StatListNode
# api boolean
+ # decorators [DecoratorNode] list of decorators
#
# with_gil boolean Acquire GIL around body
# type CFuncType
child_attrs = ["base_type", "declarator", "body", "py_func"]
inline_in_pxd = False
+ decorators = None
+ directive_locals = {}
def unqualified_name(self):
return self.entry.name
def analyse_declarations(self, env):
- if 'locals' in env.directives:
- directive_locals = env.directives['locals']
- else:
- directive_locals = {}
- self.directive_locals = directive_locals
+ if 'locals' in env.directives and env.directives['locals']:
+ self.directive_locals = env.directives['locals']
+ directive_locals = self.directive_locals
base_type = self.base_type.analyse(env)
# The 2 here is because we need both function and argument names.
name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
nogil = False,
with_gil = False,
is_overridable = True)
- cfunc = CVarDefNode(self.pos, type=cfunc_type, pxd_locals=[])
+ cfunc = CVarDefNode(self.pos, type=cfunc_type)
else:
cfunc_type = cfunc.type
if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
nogil = cfunc_type.nogil,
visibility = 'private',
api = False,
- pxd_locals = cfunc.pxd_locals)
+ directive_locals = cfunc.directive_locals)
def analyse_declarations(self, env):
if 'locals' in env.directives:
else:
err = None # allow inline function
else:
- err = None
- for stat in node.body.stats:
- if not isinstance(stat, CVarDefNode):
- err = self.ERR_INLINE_ONLY
- break
- node = CVarDefNode(node.pos,
- visibility = node.visibility,
- base_type = node.base_type,
- declarators = [node.declarator],
- in_pxd = True,
- api = node.api,
- overridable = node.overridable,
- pxd_locals = node.body.stats)
+ err = self.ERR_INLINE_ONLY
+
if err:
self.context.nonfatal_error(PostParseError(node.pos, err))
return None
return directive
# Handle decorators
- def visit_DefNode(self, node):
+ def visit_FuncDefNode(self, node):
options = []
if node.decorators:
options.append(option)
else:
realdecs.append(dec)
- node.decorators = realdecs
+ if realdecs and isinstance(node, CFuncDefNode):
+ raise PostParseError(realdecs[0].pos, "Cdef functions cannot take arbitrary decorators.")
+ else:
+ node.decorators = realdecs
if options:
optdict = {}
return self.visit_with_options(body, optdict)
else:
return self.visit_Node(node)
+
+ def visit_CVarDefNode(self, node):
+ if node.decorators:
+ for dec in node.decorators:
+ option = self.try_to_parse_option(dec.decorator)
+ if option is not None and option[0] == u'locals':
+ node.directive_locals = option[1]
+ else:
+ raise PostParseError(dec.pos, "Cdef functions can only take cython.locals() decorator.")
+ return node
# Handle with statements
def visit_WithStatNode(self, node):
lenv.declare_var(var, type, type_node.pos)
else:
error(type_node.pos, "Not a type")
- for stat in node.pxd_locals:
- stat.analyse_declarations(lenv)
node.body.analyse_declarations(lenv)
self.env_stack.append(lenv)
self.visitchildren(node)
def p_statement(s, ctx, first_statement = 0):
cdef_flag = ctx.cdef_flag
+ decorators = []
if s.sy == 'ctypedef':
if ctx.level not in ('module', 'module_pxd'):
s.error("ctypedef statement not allowed here")
elif s.sy == 'IF':
return p_IF_statement(s, ctx)
elif s.sy == 'DECORATOR':
- if ctx.level not in ('module', 'class', 'c_class', 'property'):
+ if ctx.level not in ('module', 'class', 'c_class', 'property', 'module_pxd', 'class_pxd'):
s.error('decorator not allowed here')
s.level = ctx.level
decorators = p_decorators(s)
- if s.sy != 'def':
+ if s.sy not in ('def', 'cdef', 'cpdef'):
s.error("Decorators can only be followed by functions ")
- return p_def_statement(s, decorators)
+
+ overridable = 0
+ if s.sy == 'cdef':
+ cdef_flag = 1
+ s.next()
+ if s.sy == 'cpdef':
+ cdef_flag = 1
+ overridable = 1
+ s.next()
+ if 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)):
+ s.error("Decorators can only be followed by functions ")
+ node.decorators = decorators
+ return node
else:
- overridable = 0
- if s.sy == 'cdef':
- cdef_flag = 1
- s.next()
- if s.sy == 'cpdef':
- cdef_flag = 1
- overridable = 1
- s.next()
- if cdef_flag:
- if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
- s.error('cdef statement not allowed here')
+ if ctx.api:
+ error(s.pos, "'api' not allowed with this statement")
+ elif s.sy == 'def':
+ if ctx.level not in ('module', 'class', 'c_class', 'c_class_pxd', 'property'):
+ s.error('def statement not allowed here')
s.level = ctx.level
- return p_cdef_statement(s, ctx(overridable = overridable))
+ return p_def_statement(s, decorators)
+ elif s.sy == 'class':
+ if ctx.level != 'module':
+ s.error("class definition not allowed here")
+ return p_class_statement(s)
+ 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 s.sy == 'pass' and ctx.level != 'property':
+ return p_pass_statement(s, with_newline = 1)
else:
- if ctx.api:
- error(s.pos, "'api' not allowed with this statement")
- elif s.sy == 'def':
- if ctx.level not in ('module', 'class', 'c_class', 'c_class_pxd', 'property'):
- s.error('def statement not allowed here')
- s.level = ctx.level
- return p_def_statement(s)
- elif s.sy == 'class':
- if ctx.level != 'module':
- s.error("class definition not allowed here")
- return p_class_statement(s)
- 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 s.sy == 'pass' and ctx.level != 'property':
- return p_pass_statement(s, with_newline = 1)
+ 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)
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)
- else:
- return p_simple_statement_list(
- s, ctx, first_statement = first_statement)
+ 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.