Commit 6fff2b59 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

merge

parents 82f49e1e b016353f
......@@ -16,5 +16,11 @@ class CythonScope(ModuleScope):
defining = 1,
cname='<error>')
def lookup_type(self, name):
# This function should go away when types are all first-level objects.
type = parse_basic_type(name)
if type:
return type
def create_cython_scope(context):
return CythonScope(context)
......@@ -569,6 +569,9 @@ class ExprNode(Node):
# reference, or temporary.
return self.result_in_temp()
def as_cython_attribute(self):
return None
class NewTempExprNode(ExprNode):
backwards_compatible_result = None
......@@ -780,6 +783,9 @@ class StringNode(ConstNode):
self.entry = env.add_string_const(self.value)
def analyse_as_type(self, env):
type = PyrexTypes.parse_basic_type(self.value)
if type is not None:
return type
from TreeFragment import TreeFragment
pos = (self.pos[0], self.pos[1], self.pos[2]-7)
declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
......@@ -914,7 +920,8 @@ class NameNode(AtomicExprNode):
# entry Entry Symbol table entry
# interned_cname string
is_name = 1
is_name = True
is_cython_module = False
skip_assignment_decref = False
entry = None
......@@ -960,8 +967,9 @@ class NameNode(AtomicExprNode):
return None
def analyse_as_type(self, env):
if self.name in PyrexTypes.rank_to_type_name:
return PyrexTypes.simple_c_type(1, 0, self.name)
type = PyrexTypes.parse_basic_type(self.name)
if type:
return type
entry = self.entry
if not entry:
entry = env.lookup(self.name)
......@@ -1870,6 +1878,21 @@ class SimpleCallNode(CallNode):
except Exception, e:
self.compile_time_value_error(e)
def analyse_as_type(self, env):
attr = self.function.as_cython_attribute()
if attr == 'pointer':
if len(self.args) != 1:
error(self.args.pos, "only one type allowed.")
else:
type = self.args[0].analyse_as_type(env)
if not type:
error(self.args[0].pos, "Unknown type")
else:
return PyrexTypes.CPtrType(type)
def explicit_args_kwds(self):
return self.args, None
def analyse_types(self, env):
function = self.function
function.is_called = 1
......@@ -2099,6 +2122,12 @@ class GeneralCallNode(CallNode):
except Exception, e:
self.compile_time_value_error(e)
def explicit_args_kwds(self):
if self.starstar_arg or not isinstance(self.positional_args, TupleNode):
raise PostParseError(self.pos,
'Compile-time keyword arguments must be explicit.')
return self.positional_args.args, self.keyword_args
def analyse_types(self, env):
self.function.analyse_types(env)
self.positional_args.analyse_types(env)
......@@ -2201,6 +2230,10 @@ class AttributeNode(ExprNode):
is_called = 0
needs_none_check = True
def as_cython_attribute(self):
if isinstance(self.obj, NameNode) and self.obj.is_cython_module:
return self.attribute
def coerce_to(self, dst_type, env):
# If coercing to a generic pyobject and this is a cpdef function
# we can create the corresponding attribute
......@@ -2278,9 +2311,7 @@ class AttributeNode(ExprNode):
def analyse_as_type(self, env):
module_scope = self.obj.analyse_as_module(env)
if module_scope:
entry = module_scope.lookup_here(self.attribute)
if entry and entry.is_type:
return entry.type
return module_scope.lookup_type(self.attribute)
return None
def analyse_as_extension_type(self, env):
......
......@@ -74,12 +74,13 @@ class Context:
os.path.join(os.path.dirname(__file__), '..', 'Includes'))
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 ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from ParseTreeTransforms import AlignFunctionDefinitions
from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, FinalOptimizePhase
from Buffer import IntroduceBufferAuxiliaryVars
......@@ -92,10 +93,16 @@ class Context:
_check_c_classes = check_c_classes
_specific_post_parse = None
if py and not pxd:
_align_function_definitions = AlignFunctionDefinitions(self)
else:
_align_function_definitions = None
return [
NormalizeTree(self),
PostParse(self),
_specific_post_parse,
_align_function_definitions,
InterpretCompilerDirectives(self, self.pragma_overrides),
FlattenInListTransform(),
WithTransform(self),
......@@ -112,7 +119,7 @@ class 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):
module_node.process_implementation(options, result)
result.compilation_source = module_node.compilation_source
......@@ -134,7 +141,7 @@ class Context:
return ([
create_parse(self),
] + self.create_pipeline(pxd=False) + [
] + self.create_pipeline(pxd=False, py=py) + [
inject_pxd_code,
generate_pyx_code,
])
......@@ -155,6 +162,10 @@ class Context:
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):
pipeline = self.create_pxd_pipeline(scope, module_name)
result = self.run_pipeline(pipeline, source_desc)
......@@ -504,6 +515,9 @@ def run_pipeline(source, options, full_module_name = None):
result = create_default_resultobj(source, options)
# Get pipeline
if source_desc.filename.endswith(".py"):
pipeline = context.create_py_pipeline(options, result)
else:
pipeline = context.create_pyx_pipeline(options, result)
context.setup_errors(options)
......
......@@ -412,7 +412,6 @@ class CNameDeclaratorNode(CDeclaratorNode):
elif base_type.is_void:
error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
else:
print "here"
self.name = base_type.declaration_code("", for_display=1, pyrex=1)
base_type = py_object_type
self.type = base_type
......@@ -569,9 +568,12 @@ class CArgDeclNode(Node):
is_self_arg = 0
is_generic = 1
type = None
name_declarator = None
def analyse(self, env, nonempty = 0):
#print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
if self.type is None:
# The parser may missinterpret names as types...
# We fix that here.
if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
......@@ -586,6 +588,8 @@ class CArgDeclNode(Node):
if self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name
return self.declarator.analyse(base_type, env, nonempty = nonempty)
else:
return self.name_declarator, self.type
def annotate(self, code):
if self.default:
......@@ -602,6 +606,14 @@ class CBaseTypeNode(Node):
pass
class CAnalysedBaseTypeNode(Node):
# type type
child_attrs = []
def analyse(self, env, could_be_name = False):
return self.type
class CSimpleBaseTypeNode(CBaseTypeNode):
# name string
# module_path [string] Qualifying name components
......@@ -1429,6 +1441,8 @@ class DefNode(FuncDefNode):
reqd_kw_flags_cname = "0"
is_wrapper = 0
decorators = None
entry = None
def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds)
......@@ -1444,7 +1458,44 @@ class DefNode(FuncDefNode):
self.num_required_kw_args = rk
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):
if 'locals' in env.directives:
......@@ -2235,6 +2286,43 @@ class PyClassDefNode(ClassDefNode):
bases = bases, dict = self.dict, doc = doc_node)
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):
genv = env
while env.is_py_class_scope or env.is_c_class_scope:
......@@ -2297,6 +2385,10 @@ class CClassDefNode(ClassDefNode):
child_attrs = ["body"]
buffer_defaults_node = None
buffer_defaults_pos = None
typedef_flag = False
api = False
objstruct_name = None
typeobj_name = None
def analyse_declarations(self, env):
#print "CClassDefNode.analyse_declarations:", self.class_name
......@@ -2505,8 +2597,67 @@ class SingleAssignmentNode(AssignmentNode):
child_attrs = ["lhs", "rhs"]
first = False
declaration_only = False
def analyse_declarations(self, env):
import ExprNodes
# handle declarations of the form x = cython.foo()
if isinstance(self.rhs, ExprNodes.CallNode):
func_name = self.rhs.function.as_cython_attribute()
if func_name:
args, kwds = self.rhs.explicit_args_kwds()
if func_name in ['declare', 'typedef']:
self.declaration_only = True
if len(args) != 1 or kwds is not None:
error(rhs.pos, "Can only declare one type at a time.")
return
type = args[0].analyse_as_type(env)
if type is None:
error(args[0].pos, "Unknown type")
return
lhs = self.lhs
if func_name == 'declare':
if isinstance(lhs, ExprNodes.NameNode):
vars = [(lhs.name, lhs.pos)]
elif isinstance(lhs, ExprNodes.TupleNode):
vars = [(var.name, var.pos) for var in lhs.args]
else:
error(lhs.pos, "Invalid declaration")
return
for var, pos in vars:
env.declare_var(var, type, pos, is_cdef = True)
else:
if not isinstance(lhs, ExprNodes.NameNode):
error(lhs.pos, "Invalid declaration.")
env.declare_typedef(lhs.name, type, self.pos, 'private')
elif func_name in ['struct', 'union']:
self.declaration_only = True
if len(args) > 0 or kwds is None:
error(rhs.pos, "Struct or union members must be given by name.")
return
members = []
for member, type_node in kwds.key_value_pairs:
type = type_node.analyse_as_type(env)
if type is None:
error(type_node.pos, "Unknown type")
else:
members.append((member.value, type, member.pos))
if len(members) < len(kwds.key_value_pairs):
return
if not isinstance(self.lhs, ExprNodes.NameNode):
error(self.lhs.pos, "Invalid declaration.")
name = self.lhs.name
scope = StructOrUnionScope(name)
env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
for member, type, pos in members:
scope.declare_var(member, type, pos)
if self.declaration_only:
return
else:
self.lhs.analyse_target_declaration(env)
def analyse_types(self, env, use_temp = 0):
......
......@@ -313,11 +313,19 @@ class InterpretCompilerDirectives(CythonTransform):
def visit_SingleAssignmentNode(self, node):
if (isinstance(node.rhs, ImportNode) and
node.rhs.module_name.value == u'cython'):
self.cython_module_names.add(node.lhs.name)
node = CImportStatNode(node.pos,
module_name = u'cython',
as_name = node.lhs.name)
self.visit_CImportStatNode(node)
else:
self.visitchildren(node)
return node
def visit_NameNode(self, node):
if node.name in self.cython_module_names:
node.is_cython_module = True
return node
def visit_Node(self, node):
self.visitchildren(node)
return node
......@@ -339,15 +347,7 @@ class InterpretCompilerDirectives(CythonTransform):
if optname:
optiontype = Options.option_types.get(optname)
if optiontype:
if isinstance(node, SimpleCallNode):
args = node.args
kwds = None
else:
if node.starstar_arg or not isinstance(node.positional_args, TupleNode):
raise PostParseError(dec.function.pos,
'Compile-time keyword arguments must be explicit.' % optname)
args = node.positional_args.args
kwds = node.keyword_args
args, kwds = node.explicit_args_kwds()
if optiontype is bool:
if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode):
raise PostParseError(dec.function.pos,
......@@ -574,6 +574,54 @@ class AnalyseExpressionsTransform(CythonTransform):
self.visitchildren(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):
needs_closure = False
......@@ -638,24 +686,20 @@ class EnvTransform(CythonTransform):
class TransformBuiltinMethods(EnvTransform):
def cython_attribute(self, node):
if (isinstance(node, AttributeNode) and
isinstance(node.obj, NameNode) and
node.obj.name in self.cython_module_names):
return node.attribute
def visit_ModuleNode(self, node):
self.cython_module_names = node.cython_module_names
def visit_SingleAssignmentNode(self, node):
if node.declaration_only:
return None
else:
self.visitchildren(node)
return node
def visit_AttributeNode(self, node):
attribute = self.cython_attribute(node)
attribute = node.as_cython_attribute()
if attribute:
if attribute == u'compiled':
node = BoolNode(node.pos, value=True)
else:
error(node.function.pos, u"'%s' not a valid cython attribute" % function)
error(node.pos, u"'%s' not a valid cython attribute" % attribute)
return node
def visit_SimpleCallNode(self, node):
......@@ -671,7 +715,7 @@ class TransformBuiltinMethods(EnvTransform):
return ExprNodes.DictNode(pos, key_value_pairs=items)
# cython.foo
function = self.cython_attribute(node.function)
function = node.function.as_cython_attribute()
if function:
if function == u'cast':
if len(node.args) != 2:
......@@ -691,6 +735,11 @@ class TransformBuiltinMethods(EnvTransform):
node = SizeofTypeNode(node.function.pos, arg_type=type)
else:
node = SizeofVarNode(node.function.pos, operand=node.args[0])
elif function == 'address':
if len(node.args) != 1:
error(node.function.pos, u"sizeof takes exactly one argument" % function)
else:
node = AmpersandNode(node.function.pos, operand=node.args[0])
else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function)
......
......@@ -1187,6 +1187,7 @@ modifiers_and_name_to_type = {
(2, 0, "Py_ssize_t"): c_py_ssize_t_type,
(1, 0, "long"): c_long_type,
(1, 0, "longlong"): c_longlong_type,
(1, 0, "bint"): c_bint_type,
}
......@@ -1211,6 +1212,21 @@ def simple_c_type(signed, longness, name):
# Returns None if arguments don't make sense.
return modifiers_and_name_to_type.get((signed, longness, name))
def parse_basic_type(name):
base = None
if name.startswith('p_'):
base = parse_basic_type(name[2:])
elif name.startswith('p'):
base = parse_basic_type(name[1:])
elif name.endswith('*'):
base = parse_basic_type(name[:-1])
if base:
return CPtrType(base)
elif name.startswith('u'):
return simple_c_type(0, 0, name[1:])
else:
return simple_c_type(1, 0, name)
def c_array_type(base_type, size):
# Construct a C array type.
if base_type is c_char_type:
......
......@@ -56,6 +56,7 @@ class Entry:
# 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_type boolean Is a type definition
# is_cclass boolean Is an extension class
# is_const boolean Is a constant
# is_property boolean Is a property of an extension type:
# doc_cname string or None C const holding the docstring
......@@ -108,6 +109,7 @@ class Entry:
is_cmethod = 0
is_unbound_cmethod = 0
is_type = 0
is_cclass = 0
is_const = 0
is_property = 0
doc_cname = None
......@@ -501,6 +503,11 @@ class Scope:
entry = self.declare_var(name, py_object_type, None)
return entry
def lookup_type(self, name):
entry = self.lookup(name)
if entry and entry.is_type:
return entry.type
def add_string_const(self, value, identifier = False):
# Add an entry for a string constant.
if identifier:
......@@ -989,6 +996,7 @@ class ModuleScope(Scope):
type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
entry = self.declare_type(name, type, pos, visibility = visibility,
defining = 0)
entry.is_cclass = True
if objstruct_cname:
type.objstruct_cname = objstruct_cname
elif not entry.in_cinclude:
......
......@@ -6,17 +6,157 @@ def empty_decorator(x):
def locals(**arg_types):
return empty_decorator
# Emulated language constructs
def cast(type, arg):
# can/should we emulate anything here?
if callable(type):
return type(arg)
else:
return arg
def sizeof(arg):
# can/should we emulate anything here?
return 1
def address(arg):
return pointer(type(arg))([arg])
def declare(type):
if callable(type):
return type()
else:
return None
# Emulated types
class CythonType(object):
def _pointer(self, n=1):
for i in range(n):
self = pointer(self)
return self
def __getitem__(self, ix):
return array(self, ix)
class PointerType(CythonType):
def __init__(self, value=None):
if isinstance(value, ArrayType):
self._items = [cast(self._basetype, a) for a in value._items]
elif isinstance(value, list):
self._items = [cast(self._basetype, a) for a in value]
elif value is None:
self._items = []
else:
raise ValueError
def __getitem__(self, ix):
if ix < 0:
raise IndexError, "negative indexing not allowed in C"
return self._items[ix]
def __setitem__(self, ix, value):
if ix < 0:
raise IndexError, "negative indexing not allowed in C"
self._items[ix] = cast(self._basetype, value)
class ArrayType(PointerType):
def __init__(self):
self._items = [None] * self._n
class StructType(CythonType):
def __init__(self, **data):
for key, value in data.items():
setattr(self, key, value)
def __setattr__(self, key, value):
if key in self._members:
self.__dict__[key] = cast(self._members[key], value)
else:
raise AttributeError, "Struct has no member '%s'" % key
class UnionType(CythonType):
def __init__(self, **data):
if len(data) > 0:
raise AttributeError, "Union can only store one field at a time."
for key, value in data.items():
setattr(self, key, value)
def __setattr__(self, key, value):
if key in '__dict__':
CythonType.__setattr__(self, key, value)
elif key in self._members:
self.__dict__ = {key: cast(self._members[key], value)}
else:
raise AttributeError, "Union has no member '%s'" % key
def pointer(basetype):
class PointerInstance(PointerType):
_basetype = basetype
return PointerInstance
def array(basetype, n):
class ArrayInstance(ArrayType):
_basetype = basetype
_n = n
return ArrayInstance
def struct(**members):
class StructInstance(StructType):
_members = members
for key in members.keys():
setattr(StructInstance, key, None)
return StructInstance
def union(**members):
class UnionInstance(UnionType):
_members = members
for key in members.keys():
setattr(UnionInstance, key, None)
return UnionInstance
class typedef(CythonType):
def __init__(self, type):
self._basetype = type
def __call__(self, value=None):
if value is not None:
value = cast(self._basetype, value)
return value
py_int = int
py_long = long
py_float = float
# They just have to exist...
int = long = char = bint = uint = ulong = longlong = ulonglong = Py_ssize_t = float = double = None
# Predefined types
int_types = ['char', 'short', 'int', 'long', 'longlong', 'Py_ssize_t']
float_types = ['double', 'float']
other_types = ['bint', 'Py_ssize_t', 'void']
gs = globals()
for name in int_types:
gs[name] = typedef(py_int)
gs['u'+name] = typedef(py_int)
double = float = typedef(py_float)
bint = typedef(bool)
void = typedef(int)
for t in int_types + float_types + other_types:
for i in range(1, 4):
gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i)
void = typedef(None)
NULL = None
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