Commit 3bcf8140 authored by Robert Bradshaw's avatar Robert Bradshaw

Allow .pxd file to set c signatures for .py files.

parent a7b92caa
...@@ -74,12 +74,13 @@ class Context: ...@@ -74,12 +74,13 @@ class Context:
os.path.join(os.path.dirname(__file__), '..', 'Includes')) os.path.join(os.path.dirname(__file__), '..', 'Includes'))
self.include_directories = include_directories + [standard_include_path] self.include_directories = include_directories + [standard_include_path]
def create_pipeline(self, pxd): def create_pipeline(self, pxd, py=False):
from Visitor import PrintTree from Visitor import PrintTree
from ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse from ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from ParseTreeTransforms import AlignFunctionDefinitions
from AutoDocTransforms import EmbedSignature from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, FinalOptimizePhase from Optimize import FlattenInListTransform, SwitchTransform, FinalOptimizePhase
from Buffer import IntroduceBufferAuxiliaryVars from Buffer import IntroduceBufferAuxiliaryVars
...@@ -92,10 +93,16 @@ class Context: ...@@ -92,10 +93,16 @@ class Context:
_check_c_classes = check_c_classes _check_c_classes = check_c_classes
_specific_post_parse = None _specific_post_parse = None
if py and not pxd:
_align_function_definitions = AlignFunctionDefinitions(self)
else:
_align_function_definitions = None
return [ return [
NormalizeTree(self), NormalizeTree(self),
PostParse(self), PostParse(self),
_specific_post_parse, _specific_post_parse,
_align_function_definitions,
InterpretCompilerDirectives(self, self.pragma_overrides), InterpretCompilerDirectives(self, self.pragma_overrides),
FlattenInListTransform(), FlattenInListTransform(),
WithTransform(self), WithTransform(self),
...@@ -112,7 +119,7 @@ class Context: ...@@ -112,7 +119,7 @@ class Context:
# CreateClosureClasses(context), # CreateClosureClasses(context),
] ]
def create_pyx_pipeline(self, options, result): def create_pyx_pipeline(self, options, result, py=False):
def generate_pyx_code(module_node): def generate_pyx_code(module_node):
module_node.process_implementation(options, result) module_node.process_implementation(options, result)
result.compilation_source = module_node.compilation_source result.compilation_source = module_node.compilation_source
...@@ -134,7 +141,7 @@ class Context: ...@@ -134,7 +141,7 @@ class Context:
return ([ return ([
create_parse(self), create_parse(self),
] + self.create_pipeline(pxd=False) + [ ] + self.create_pipeline(pxd=False, py=py) + [
inject_pxd_code, inject_pxd_code,
generate_pyx_code, generate_pyx_code,
]) ])
...@@ -155,6 +162,10 @@ class Context: ...@@ -155,6 +162,10 @@ class Context:
ExtractPxdCode(self), ExtractPxdCode(self),
] ]
def create_py_pipeline(self, options, result):
return self.create_pyx_pipeline(options, result, py=True)
def process_pxd(self, source_desc, scope, module_name): def process_pxd(self, source_desc, scope, module_name):
pipeline = self.create_pxd_pipeline(scope, module_name) pipeline = self.create_pxd_pipeline(scope, module_name)
result = self.run_pipeline(pipeline, source_desc) result = self.run_pipeline(pipeline, source_desc)
...@@ -504,6 +515,9 @@ def run_pipeline(source, options, full_module_name = None): ...@@ -504,6 +515,9 @@ def run_pipeline(source, options, full_module_name = None):
result = create_default_resultobj(source, options) result = create_default_resultobj(source, options)
# Get pipeline # Get pipeline
if source_desc.filename.endswith(".py"):
pipeline = context.create_py_pipeline(options, result)
else:
pipeline = context.create_pyx_pipeline(options, result) pipeline = context.create_pyx_pipeline(options, result)
context.setup_errors(options) context.setup_errors(options)
......
...@@ -412,7 +412,6 @@ class CNameDeclaratorNode(CDeclaratorNode): ...@@ -412,7 +412,6 @@ class CNameDeclaratorNode(CDeclaratorNode):
elif base_type.is_void: elif base_type.is_void:
error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.") error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
else: else:
print "here"
self.name = base_type.declaration_code("", for_display=1, pyrex=1) self.name = base_type.declaration_code("", for_display=1, pyrex=1)
base_type = py_object_type base_type = py_object_type
self.type = base_type self.type = base_type
...@@ -569,9 +568,12 @@ class CArgDeclNode(Node): ...@@ -569,9 +568,12 @@ class CArgDeclNode(Node):
is_self_arg = 0 is_self_arg = 0
is_generic = 1 is_generic = 1
type = None
name_declarator = None
def analyse(self, env, nonempty = 0): def analyse(self, env, nonempty = 0):
#print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ### #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
if self.type is None:
# The parser may missinterpret names as types... # The parser may missinterpret names as types...
# We fix that here. # We fix that here.
if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '': if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
...@@ -586,6 +588,8 @@ class CArgDeclNode(Node): ...@@ -586,6 +588,8 @@ class CArgDeclNode(Node):
if self.base_type.arg_name: if self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name self.declarator.name = self.base_type.arg_name
return self.declarator.analyse(base_type, env, nonempty = nonempty) return self.declarator.analyse(base_type, env, nonempty = nonempty)
else:
return self.name_declarator, self.type
def annotate(self, code): def annotate(self, code):
if self.default: if self.default:
...@@ -602,6 +606,14 @@ class CBaseTypeNode(Node): ...@@ -602,6 +606,14 @@ class CBaseTypeNode(Node):
pass pass
class CAnalysedBaseTypeNode(Node):
# type type
child_attrs = []
def analyse(self, env, could_be_name = False):
return self.type
class CSimpleBaseTypeNode(CBaseTypeNode): class CSimpleBaseTypeNode(CBaseTypeNode):
# name string # name string
# module_path [string] Qualifying name components # module_path [string] Qualifying name components
...@@ -1429,6 +1441,8 @@ class DefNode(FuncDefNode): ...@@ -1429,6 +1441,8 @@ class DefNode(FuncDefNode):
reqd_kw_flags_cname = "0" reqd_kw_flags_cname = "0"
is_wrapper = 0 is_wrapper = 0
decorators = None decorators = None
entry = None
def __init__(self, pos, **kwds): def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds) FuncDefNode.__init__(self, pos, **kwds)
...@@ -1444,7 +1458,44 @@ class DefNode(FuncDefNode): ...@@ -1444,7 +1458,44 @@ class DefNode(FuncDefNode):
self.num_required_kw_args = rk self.num_required_kw_args = rk
self.num_required_args = r self.num_required_args = r
entry = None def as_cfunction(self, cfunc):
if self.star_arg:
error(self.star_arg.pos, "cdef function cannot have star argument")
if self.starstar_arg:
error(self.starstar_arg.pos, "cdef function cannot have starstar argument")
if len(self.args) != len(cfunc.type.args) or cfunc.type.has_varargs:
error(self.pos, "wrong number of arguments")
error(declarator.pos, "previous declaration here")
for formal_arg, type_arg in zip(self.args, cfunc.type.args):
name_declarator, type = formal_arg.analyse(cfunc.scope, nonempty=1)
if type is PyrexTypes.py_object_type or formal_arg.is_self:
formal_arg.type = type_arg.type
formal_arg.name_declarator = name_declarator
import ExprNodes
if cfunc.type.exception_value is None:
exception_value = None
else:
exception_value = ExprNodes.ConstNode(self.pos, value=cfunc.type.exception_value, type=cfunc.type.return_type)
declarator = CFuncDeclaratorNode(self.pos,
base = CNameDeclaratorNode(self.pos, name=self.name, cname=None),
args = self.args,
has_varargs = False,
exception_check = cfunc.type.exception_check,
exception_value = exception_value,
with_gil = cfunc.type.with_gil,
nogil = cfunc.type.nogil)
return CFuncDefNode(self.pos,
modifiers = [],
base_type = CAnalysedBaseTypeNode(self.pos, type=cfunc.type.return_type),
declarator = declarator,
body = self.body,
doc = self.doc,
overridable = cfunc.type.is_overridable,
type = cfunc.type,
with_gil = cfunc.type.with_gil,
nogil = cfunc.type.nogil,
visibility = 'private',
api = False)
def analyse_declarations(self, env): def analyse_declarations(self, env):
if 'locals' in env.directives: if 'locals' in env.directives:
...@@ -2235,6 +2286,43 @@ class PyClassDefNode(ClassDefNode): ...@@ -2235,6 +2286,43 @@ class PyClassDefNode(ClassDefNode):
bases = bases, dict = self.dict, doc = doc_node) bases = bases, dict = self.dict, doc = doc_node)
self.target = ExprNodes.NameNode(pos, name = name) self.target = ExprNodes.NameNode(pos, name = name)
def as_cclass(self):
"""
Return this node as if it were declared as an extension class"
"""
bases = self.classobj.bases.args
if len(bases) == 0:
base_class_name = None
base_class_module = None
elif len(bases) == 1:
base = bases[0]
path = []
while isinstance(base, ExprNodes.AttributeNode):
path.insert(0, base.attribute)
base = base.obj
if isinstance(base, ExprNodes.NameNode):
path.insert(0, base.name)
base_class_name = path[-1]
if len(path) > 1:
base_class_module = u'.'.join(path[:-1])
else:
base_class_module = None
else:
error(self.classobj.bases.args.pos, "Invalid base class")
else:
error(self.classobj.bases.args.pos, "C class may only have one base class")
return None
return CClassDefNode(self.pos,
visibility = 'private',
module_name = None,
class_name = self.name,
base_class_module = base_class_module,
base_class_name = base_class_name,
body = self.body,
in_pxd = False,
doc = self.doc)
def create_scope(self, env): def create_scope(self, env):
genv = env genv = env
while env.is_py_class_scope or env.is_c_class_scope: while env.is_py_class_scope or env.is_c_class_scope:
...@@ -2297,6 +2385,10 @@ class CClassDefNode(ClassDefNode): ...@@ -2297,6 +2385,10 @@ class CClassDefNode(ClassDefNode):
child_attrs = ["body"] child_attrs = ["body"]
buffer_defaults_node = None buffer_defaults_node = None
buffer_defaults_pos = None buffer_defaults_pos = None
typedef_flag = False
api = False
objstruct_name = None
typeobj_name = None
def analyse_declarations(self, env): def analyse_declarations(self, env):
#print "CClassDefNode.analyse_declarations:", self.class_name #print "CClassDefNode.analyse_declarations:", self.class_name
......
...@@ -574,6 +574,54 @@ class AnalyseExpressionsTransform(CythonTransform): ...@@ -574,6 +574,54 @@ class AnalyseExpressionsTransform(CythonTransform):
self.visitchildren(node) self.visitchildren(node)
return node return node
class AlignFunctionDefinitions(CythonTransform):
"""
This class takes the signatures from a .pxd file and applies them to
the def methods in a .py file.
"""
def visit_ModuleNode(self, node):
self.scope = node.scope
self.visitchildren(node)
return node
def visit_PyClassDefNode(self, node):
pxd_def = self.scope.lookup(node.name)
if pxd_def:
if pxd_def.is_cclass:
return self.visit_CClassDefNode(node.as_cclass(), pxd_def)
else:
error(node.pos, "'%s' redeclared" % node.name)
error(pxd_def.pos, "previous declaration here")
return None
self.visitchildren(node)
return node
def visit_CClassDefNode(self, node, pxd_def=None):
if pxd_def is None:
pxd_def = self.scope.lookup(node.class_name)
if pxd_def:
outer_scope = self.scope
self.scope = pxd_def.type.scope
self.visitchildren(node)
if pxd_def:
self.scope = outer_scope
return node
def visit_DefNode(self, node):
pxd_def = self.scope.lookup(node.name)
if pxd_def:
if pxd_def.is_cfunction:
node = node.as_cfunction(pxd_def)
else:
error(node.pos, "'%s' redeclared" % node.name)
error(pxd_def.pos, "previous declaration here")
return None
# Enable this when internal def functions are allowed.
# self.visitchildren(node)
return node
class MarkClosureVisitor(CythonTransform): class MarkClosureVisitor(CythonTransform):
needs_closure = False needs_closure = False
......
...@@ -56,6 +56,7 @@ class Entry: ...@@ -56,6 +56,7 @@ class Entry:
# is_cmethod boolean Is a C method of an extension type # is_cmethod boolean Is a C method of an extension type
# is_unbound_cmethod boolean Is an unbound C method of an extension type # is_unbound_cmethod boolean Is an unbound C method of an extension type
# is_type boolean Is a type definition # is_type boolean Is a type definition
# is_cclass boolean Is an extension class
# is_const boolean Is a constant # is_const boolean Is a constant
# is_property boolean Is a property of an extension type: # is_property boolean Is a property of an extension type:
# doc_cname string or None C const holding the docstring # doc_cname string or None C const holding the docstring
...@@ -108,6 +109,7 @@ class Entry: ...@@ -108,6 +109,7 @@ class Entry:
is_cmethod = 0 is_cmethod = 0
is_unbound_cmethod = 0 is_unbound_cmethod = 0
is_type = 0 is_type = 0
is_cclass = 0
is_const = 0 is_const = 0
is_property = 0 is_property = 0
doc_cname = None doc_cname = None
...@@ -989,6 +991,7 @@ class ModuleScope(Scope): ...@@ -989,6 +991,7 @@ class ModuleScope(Scope):
type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name) type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
entry = self.declare_type(name, type, pos, visibility = visibility, entry = self.declare_type(name, type, pos, visibility = visibility,
defining = 0) defining = 0)
entry.is_cclass = True
if objstruct_cname: if objstruct_cname:
type.objstruct_cname = objstruct_cname type.objstruct_cname = objstruct_cname
elif not entry.in_cinclude: elif not entry.in_cinclude:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment