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

merge

parents 82f49e1e b016353f
...@@ -15,6 +15,12 @@ class CythonScope(ModuleScope): ...@@ -15,6 +15,12 @@ class CythonScope(ModuleScope):
pos=None, pos=None,
defining = 1, defining = 1,
cname='<error>') 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): def create_cython_scope(context):
return CythonScope(context) return CythonScope(context)
...@@ -568,6 +568,9 @@ class ExprNode(Node): ...@@ -568,6 +568,9 @@ class ExprNode(Node):
# a constant, local var, C global var, struct member # a constant, local var, C global var, struct member
# reference, or temporary. # reference, or temporary.
return self.result_in_temp() return self.result_in_temp()
def as_cython_attribute(self):
return None
class NewTempExprNode(ExprNode): class NewTempExprNode(ExprNode):
...@@ -780,6 +783,9 @@ class StringNode(ConstNode): ...@@ -780,6 +783,9 @@ class StringNode(ConstNode):
self.entry = env.add_string_const(self.value) self.entry = env.add_string_const(self.value)
def analyse_as_type(self, env): def analyse_as_type(self, env):
type = PyrexTypes.parse_basic_type(self.value)
if type is not None:
return type
from TreeFragment import TreeFragment from TreeFragment import TreeFragment
pos = (self.pos[0], self.pos[1], self.pos[2]-7) 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) declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
...@@ -914,7 +920,8 @@ class NameNode(AtomicExprNode): ...@@ -914,7 +920,8 @@ class NameNode(AtomicExprNode):
# entry Entry Symbol table entry # entry Entry Symbol table entry
# interned_cname string # interned_cname string
is_name = 1 is_name = True
is_cython_module = False
skip_assignment_decref = False skip_assignment_decref = False
entry = None entry = None
...@@ -960,8 +967,9 @@ class NameNode(AtomicExprNode): ...@@ -960,8 +967,9 @@ class NameNode(AtomicExprNode):
return None return None
def analyse_as_type(self, env): def analyse_as_type(self, env):
if self.name in PyrexTypes.rank_to_type_name: type = PyrexTypes.parse_basic_type(self.name)
return PyrexTypes.simple_c_type(1, 0, self.name) if type:
return type
entry = self.entry entry = self.entry
if not entry: if not entry:
entry = env.lookup(self.name) entry = env.lookup(self.name)
...@@ -1869,6 +1877,21 @@ class SimpleCallNode(CallNode): ...@@ -1869,6 +1877,21 @@ class SimpleCallNode(CallNode):
return function(*args) return function(*args)
except Exception, e: except Exception, e:
self.compile_time_value_error(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): def analyse_types(self, env):
function = self.function function = self.function
...@@ -2098,6 +2121,12 @@ class GeneralCallNode(CallNode): ...@@ -2098,6 +2121,12 @@ class GeneralCallNode(CallNode):
return function(*positional_args, **keyword_args) return function(*positional_args, **keyword_args)
except Exception, e: except Exception, e:
self.compile_time_value_error(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): def analyse_types(self, env):
self.function.analyse_types(env) self.function.analyse_types(env)
...@@ -2201,6 +2230,10 @@ class AttributeNode(ExprNode): ...@@ -2201,6 +2230,10 @@ class AttributeNode(ExprNode):
is_called = 0 is_called = 0
needs_none_check = True 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): def coerce_to(self, dst_type, env):
# If coercing to a generic pyobject and this is a cpdef function # If coercing to a generic pyobject and this is a cpdef function
# we can create the corresponding attribute # we can create the corresponding attribute
...@@ -2278,9 +2311,7 @@ class AttributeNode(ExprNode): ...@@ -2278,9 +2311,7 @@ class AttributeNode(ExprNode):
def analyse_as_type(self, env): def analyse_as_type(self, env):
module_scope = self.obj.analyse_as_module(env) module_scope = self.obj.analyse_as_module(env)
if module_scope: if module_scope:
entry = module_scope.lookup_here(self.attribute) return module_scope.lookup_type(self.attribute)
if entry and entry.is_type:
return entry.type
return None return None
def analyse_as_extension_type(self, env): def analyse_as_extension_type(self, env):
......
...@@ -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
...@@ -91,11 +92,17 @@ class Context: ...@@ -91,11 +92,17 @@ class Context:
else: else:
_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,
]) ])
...@@ -154,6 +161,10 @@ class Context: ...@@ -154,6 +161,10 @@ class Context:
return [parse_pxd] + self.create_pipeline(pxd=True) + [ return [parse_pxd] + self.create_pipeline(pxd=True) + [
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)
...@@ -504,7 +515,10 @@ def run_pipeline(source, options, full_module_name = None): ...@@ -504,7 +515,10 @@ 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
pipeline = context.create_pyx_pipeline(options, result) 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) context.setup_errors(options)
err, enddata = context.run_pipeline(pipeline, source) err, enddata = context.run_pipeline(pipeline, source)
......
...@@ -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,23 +568,28 @@ class CArgDeclNode(Node): ...@@ -569,23 +568,28 @@ 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 ###
# The parser may missinterpret names as types... if self.type is None:
# We fix that here. # The parser may missinterpret names as types...
if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '': # We fix that here.
if nonempty: if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
self.declarator.name = self.base_type.name if nonempty:
self.base_type.name = None self.declarator.name = self.base_type.name
self.base_type.is_basic_c_type = False self.base_type.name = None
could_be_name = True self.base_type.is_basic_c_type = False
could_be_name = True
else:
could_be_name = False
base_type = self.base_type.analyse(env, could_be_name = could_be_name)
if self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name
return self.declarator.analyse(base_type, env, nonempty = nonempty)
else: else:
could_be_name = False return self.name_declarator, self.type
base_type = self.base_type.analyse(env, could_be_name = could_be_name)
if self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name
return self.declarator.analyse(base_type, env, nonempty = nonempty)
def annotate(self, code): def annotate(self, code):
if self.default: if self.default:
...@@ -601,6 +605,14 @@ class CBaseTypeNode(Node): ...@@ -601,6 +605,14 @@ class CBaseTypeNode(Node):
# Returns the type. # Returns the type.
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
...@@ -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)
...@@ -1443,8 +1457,45 @@ class DefNode(FuncDefNode): ...@@ -1443,8 +1457,45 @@ class DefNode(FuncDefNode):
self.num_kwonly_args = k self.num_kwonly_args = k
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
...@@ -2505,9 +2597,68 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -2505,9 +2597,68 @@ class SingleAssignmentNode(AssignmentNode):
child_attrs = ["lhs", "rhs"] child_attrs = ["lhs", "rhs"]
first = False first = False
declaration_only = False
def analyse_declarations(self, env): def analyse_declarations(self, env):
self.lhs.analyse_target_declaration(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): def analyse_types(self, env, use_temp = 0):
self.rhs.analyse_types(env) self.rhs.analyse_types(env)
......
...@@ -313,10 +313,18 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -313,10 +313,18 @@ class InterpretCompilerDirectives(CythonTransform):
def visit_SingleAssignmentNode(self, node): def visit_SingleAssignmentNode(self, node):
if (isinstance(node.rhs, ImportNode) and if (isinstance(node.rhs, ImportNode) and
node.rhs.module_name.value == u'cython'): 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: else:
self.visitchildren(node) self.visitchildren(node)
return 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): def visit_Node(self, node):
self.visitchildren(node) self.visitchildren(node)
...@@ -339,15 +347,7 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -339,15 +347,7 @@ class InterpretCompilerDirectives(CythonTransform):
if optname: if optname:
optiontype = Options.option_types.get(optname) optiontype = Options.option_types.get(optname)
if optiontype: if optiontype:
if isinstance(node, SimpleCallNode): args, kwds = node.explicit_args_kwds()
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
if optiontype is bool: if optiontype is bool:
if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode): if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode):
raise PostParseError(dec.function.pos, raise PostParseError(dec.function.pos,
...@@ -516,7 +516,7 @@ property NAME: ...@@ -516,7 +516,7 @@ property NAME:
node.analyse_declarations(self.env_stack[-1]) node.analyse_declarations(self.env_stack[-1])
self.visitchildren(node) self.visitchildren(node)
return node return node
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
lenv = node.create_local_scope(self.env_stack[-1]) lenv = node.create_local_scope(self.env_stack[-1])
node.body.analyse_control_flow(lenv) # this will be totally refactored node.body.analyse_control_flow(lenv) # this will be totally refactored
...@@ -573,6 +573,54 @@ class AnalyseExpressionsTransform(CythonTransform): ...@@ -573,6 +573,54 @@ class AnalyseExpressionsTransform(CythonTransform):
node.body.analyse_expressions(node.local_scope) node.body.analyse_expressions(node.local_scope)
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):
...@@ -638,24 +686,20 @@ class EnvTransform(CythonTransform): ...@@ -638,24 +686,20 @@ class EnvTransform(CythonTransform):
class TransformBuiltinMethods(EnvTransform): class TransformBuiltinMethods(EnvTransform):
def cython_attribute(self, node): def visit_SingleAssignmentNode(self, node):
if (isinstance(node, AttributeNode) and if node.declaration_only:
isinstance(node.obj, NameNode) and return None
node.obj.name in self.cython_module_names): else:
return node.attribute self.visitchildren(node)
return node
def visit_ModuleNode(self, node):
self.cython_module_names = node.cython_module_names
self.visitchildren(node)
return node
def visit_AttributeNode(self, node): def visit_AttributeNode(self, node):
attribute = self.cython_attribute(node) attribute = node.as_cython_attribute()
if attribute: if attribute:
if attribute == u'compiled': if attribute == u'compiled':
node = BoolNode(node.pos, value=True) node = BoolNode(node.pos, value=True)
else: 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 return node
def visit_SimpleCallNode(self, node): def visit_SimpleCallNode(self, node):
...@@ -671,7 +715,7 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -671,7 +715,7 @@ class TransformBuiltinMethods(EnvTransform):
return ExprNodes.DictNode(pos, key_value_pairs=items) return ExprNodes.DictNode(pos, key_value_pairs=items)
# cython.foo # cython.foo
function = self.cython_attribute(node.function) function = node.function.as_cython_attribute()
if function: if function:
if function == u'cast': if function == u'cast':
if len(node.args) != 2: if len(node.args) != 2:
...@@ -691,6 +735,11 @@ class TransformBuiltinMethods(EnvTransform): ...@@ -691,6 +735,11 @@ class TransformBuiltinMethods(EnvTransform):
node = SizeofTypeNode(node.function.pos, arg_type=type) node = SizeofTypeNode(node.function.pos, arg_type=type)
else: else:
node = SizeofVarNode(node.function.pos, operand=node.args[0]) 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: else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function) error(node.function.pos, u"'%s' not a valid cython language construct" % function)
......
...@@ -1187,6 +1187,7 @@ modifiers_and_name_to_type = { ...@@ -1187,6 +1187,7 @@ modifiers_and_name_to_type = {
(2, 0, "Py_ssize_t"): c_py_ssize_t_type, (2, 0, "Py_ssize_t"): c_py_ssize_t_type,
(1, 0, "long"): c_long_type, (1, 0, "long"): c_long_type,
(1, 0, "longlong"): c_longlong_type,
(1, 0, "bint"): c_bint_type, (1, 0, "bint"): c_bint_type,
} }
...@@ -1210,6 +1211,21 @@ def simple_c_type(signed, longness, name): ...@@ -1210,6 +1211,21 @@ def simple_c_type(signed, longness, name):
# Find type descriptor for simple type given name and modifiers. # Find type descriptor for simple type given name and modifiers.
# Returns None if arguments don't make sense. # Returns None if arguments don't make sense.
return modifiers_and_name_to_type.get((signed, longness, name)) 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): def c_array_type(base_type, size):
# Construct a C array type. # Construct a C array type.
......
...@@ -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
...@@ -500,6 +502,11 @@ class Scope: ...@@ -500,6 +502,11 @@ class Scope:
if not entry: if not entry:
entry = self.declare_var(name, py_object_type, None) entry = self.declare_var(name, py_object_type, None)
return entry 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): def add_string_const(self, value, identifier = False):
# Add an entry for a string constant. # Add an entry for a string constant.
...@@ -989,6 +996,7 @@ class ModuleScope(Scope): ...@@ -989,6 +996,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:
......
...@@ -6,17 +6,157 @@ def empty_decorator(x): ...@@ -6,17 +6,157 @@ def empty_decorator(x):
def locals(**arg_types): def locals(**arg_types):
return empty_decorator return empty_decorator
# Emulated language constructs
def cast(type, arg): def cast(type, arg):
# can/should we emulate anything here? if callable(type):
return arg return type(arg)
else:
return arg
def sizeof(arg): def sizeof(arg):
# can/should we emulate anything here?
return 1 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_int = int
py_long = long py_long = long
py_float = float 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