Commit fde67796 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

merge

parents c84a953c 3bbefcb4
import re
from Cython.Compiler.Visitor import CythonTransform from Cython.Compiler.Visitor import CythonTransform
from Cython.Compiler.Nodes import DefNode, CFuncDefNode from Cython.Compiler.Nodes import DefNode, CFuncDefNode
from Cython.Compiler.Errors import CompileError from Cython.Compiler.Errors import CompileError
from Cython.Compiler.StringEncoding import EncodedString from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler import Options from Cython.Compiler import Options
from Cython.Compiler import PyrexTypes
class EmbedSignature(CythonTransform):
SPECIAL_METHOD_RE = re.compile(r'__\w+__') class EmbedSignature(CythonTransform):
def __init__(self, context): def __init__(self, context):
super(EmbedSignature, self).__init__(context) super(EmbedSignature, self).__init__(context)
self.denv = None # XXX self.denv = None # XXX
self.is_in_class = False
self.class_name = None self.class_name = None
def _fmt_basic_c_type_modifiers(self, ctype):
longness = ctype.longness
modifiers = ''
if longness < 0:
modifiers = 'short '
elif longness > 0:
modifiers = 'long ' * longness
signed = ctype.signed
if signed == 0:
modifiers = 'unsigned ' + modifiers
elif signed == 2:
modifiers = 'signed ' + modifiers
return modifiers[:-1] # strip final space
def _fmt_arg_type(self, arg):
try:
base_type = arg.base_type
arg_type = base_type.name
except AttributeError:
return ''
if base_type.is_basic_c_type:
modifiers = self._fmt_basic_c_type_modifiers(base_type)
if modifiers:
arg_type = '%s %s' % (modifiers, arg_type)
return arg_type
def _fmt_arg_name(self, arg):
try:
return arg.declarator.name
except AttributeError:
return arg.declarator.base.name
def _fmt_arg_defv(self, arg): def _fmt_arg_defv(self, arg):
if not arg.default: if not arg.default:
return None return None
...@@ -63,14 +28,14 @@ class EmbedSignature(CythonTransform): ...@@ -63,14 +28,14 @@ class EmbedSignature(CythonTransform):
return '<???>' return '<???>'
def _fmt_arg(self, arg): def _fmt_arg(self, arg):
arg_type = self._fmt_arg_type(arg) if arg.type is PyrexTypes.py_object_type or arg.is_self_arg:
arg_name = self._fmt_arg_name(arg) doc = arg.name
arg_defv = self._fmt_arg_defv(arg) else:
doc = arg_name doc = arg.type.declaration_code(arg.name, for_display=1)
if arg_type: if arg.default:
doc = ('%s ' % arg_type) + doc arg_defv = self._fmt_arg_defv(arg)
if arg_defv: if arg_defv:
doc = doc + ('=%s' % arg_defv) doc = doc + ('=%s' % arg_defv)
return doc return doc
def _fmt_arglist(self, args, def _fmt_arglist(self, args,
...@@ -89,13 +54,10 @@ class EmbedSignature(CythonTransform): ...@@ -89,13 +54,10 @@ class EmbedSignature(CythonTransform):
return arglist return arglist
def _fmt_ret_type(self, ret): def _fmt_ret_type(self, ret):
ret_type = ret.name if ret is PyrexTypes.py_object_type:
if ret_type is None: return None
return '' else:
modifiers = self._fmt_basic_c_type_modifiers(ret) return ret.declaration_code("", for_display=1)
if modifiers:
ret_type = '%s %s' % (modifiers, ret_type)
return ret_type
def _fmt_signature(self, cls_name, func_name, args, def _fmt_signature(self, cls_name, func_name, args,
npargs=0, pargs=None, npargs=0, pargs=None,
...@@ -128,9 +90,7 @@ class EmbedSignature(CythonTransform): ...@@ -128,9 +90,7 @@ class EmbedSignature(CythonTransform):
return super(EmbedSignature, self).__call__(node) return super(EmbedSignature, self).__call__(node)
def visit_ClassDefNode(self, node): def visit_ClassDefNode(self, node):
oldincls = self.is_in_class
oldname = self.class_name oldname = self.class_name
self.is_in_class = True
try: try:
# PyClassDefNode # PyClassDefNode
self.class_name = node.name self.class_name = node.name
...@@ -138,7 +98,6 @@ class EmbedSignature(CythonTransform): ...@@ -138,7 +98,6 @@ class EmbedSignature(CythonTransform):
# CClassDefNode # CClassDefNode
self.class_name = node.class_name self.class_name = node.class_name
self.visitchildren(node) self.visitchildren(node)
self.is_in_class = oldincls
self.class_name = oldname self.class_name = oldname
return node return node
...@@ -148,9 +107,7 @@ class EmbedSignature(CythonTransform): ...@@ -148,9 +107,7 @@ class EmbedSignature(CythonTransform):
signature = None signature = None
if type(node) is DefNode: # def FOO(...): if type(node) is DefNode: # def FOO(...):
special_method = (self.is_in_class and \ if not node.entry.is_special:
self.SPECIAL_METHOD_RE.match(node.name))
if not special_method:
nkargs = getattr(node, 'num_kwonly_args', 0) nkargs = getattr(node, 'num_kwonly_args', 0)
npargs = len(node.args) - nkargs npargs = len(node.args) - nkargs
signature = self._fmt_signature( signature = self._fmt_signature(
...@@ -163,10 +120,12 @@ class EmbedSignature(CythonTransform): ...@@ -163,10 +120,12 @@ class EmbedSignature(CythonTransform):
signature = self._fmt_signature( signature = self._fmt_signature(
self.class_name, node.declarator.base.name, self.class_name, node.declarator.base.name,
node.declarator.args, node.declarator.args,
return_type=node.base_type) return_type=node.return_type)
else: # should not fall here ... else: # should not fall here ...
assert False assert False
if signature: if signature:
new_doc = self._embed_signature(signature, node.doc) new_doc = self._embed_signature(signature, node.entry.doc)
node.doc = EncodedString(new_doc) # XXX node.entry.doc = EncodedString(new_doc)
if hasattr(node, 'py_func') and node.py_func is not None:
node.py_func.entry.doc = EncodedString(new_doc)
return node return node
...@@ -30,6 +30,7 @@ builtin_function_table = [ ...@@ -30,6 +30,7 @@ builtin_function_table = [
('issubclass', "OO", "b", "PyObject_IsSubclass"), ('issubclass', "OO", "b", "PyObject_IsSubclass"),
('iter', "O", "O", "PyObject_GetIter"), ('iter', "O", "O", "PyObject_GetIter"),
('len', "O", "Z", "PyObject_Length"), ('len', "O", "Z", "PyObject_Length"),
('locals', "", "O", "__pyx_locals"),
#('map', "", "", ""), #('map', "", "", ""),
#('max', "", "", ""), #('max', "", "", ""),
#('min', "", "", ""), #('min', "", "", ""),
...@@ -82,23 +83,34 @@ builtin_function_table = [ ...@@ -82,23 +83,34 @@ builtin_function_table = [
builtin_types_table = [ builtin_types_table = [
("type", "PyType_Type", []), ("type", "PyType_Type", []),
# ("str", "PyBytes_Type", []),
("bool", "PyBool_Type", []),
("int", "PyInt_Type", []),
("long", "PyLong_Type", []),
("float", "PyFloat_Type", []),
("complex", "PyComplex_Type", []),
("bytes", "PyBytes_Type", []),
("str", "PyString_Type", []),
("unicode", "PyUnicode_Type", []), ("unicode", "PyUnicode_Type", []),
("file", "PyFile_Type", []),
# ("slice", "PySlice_Type", []),
# ("set", "PySet_Type", []),
("frozenset", "PyFrozenSet_Type", []),
("tuple", "PyTuple_Type", []), ("tuple", "PyTuple_Type", []),
("list", "PyList_Type", [("append", "OO", "i", "PyList_Append"), ("list", "PyList_Type", [("append", "OO", "i", "PyList_Append"),
("insert", "OiO", "i", "PyList_Insert"), ("insert", "OiO", "i", "PyList_Insert"),
("sort", "O", "i", "PyList_Sort"), ("sort", "O", "i", "PyList_Sort"),
("reverse","O", "i", "PyList_Reverse")]), ("reverse","O", "i", "PyList_Reverse")]),
("dict", "PyDict_Type", [("items", "O", "O", "PyDict_Items"), ("dict", "PyDict_Type", [("items", "O", "O", "PyDict_Items"),
("keys", "O", "O", "PyDict_Keys"), ("keys", "O", "O", "PyDict_Keys"),
("values","O", "O", "PyDict_Values")]), ("values","O", "O", "PyDict_Values")]),
("set", "PySet_Type", []),
("frozenset", "PyFrozenSet_Type", []),
("slice", "PySlice_Type", []),
("file", "PyFile_Type", []),
] ]
builtin_structs_table = [ builtin_structs_table = [
......
...@@ -190,13 +190,12 @@ class GlobalState(object): ...@@ -190,13 +190,12 @@ class GlobalState(object):
self.init_cached_builtins_writer.putln("static int __Pyx_InitCachedBuiltins(void) {") self.init_cached_builtins_writer.putln("static int __Pyx_InitCachedBuiltins(void) {")
self.initwriter.enter_cfunc_scope() self.initwriter.enter_cfunc_scope()
self.initwriter.putln("").putln("static int __Pyx_InitGlobals(void) {") self.initwriter.putln("")
self.initwriter.putln("static int __Pyx_InitGlobals(void) {")
(self.pystring_table self.pystring_table.putln("")
.putln("") self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
.putln("static __Pyx_StringTabEntry %s[] = {" %
Naming.stringtab_cname) Naming.stringtab_cname)
)
# #
# Global constants, interned objects, etc. # Global constants, interned objects, etc.
...@@ -208,7 +207,8 @@ class GlobalState(object): ...@@ -208,7 +207,8 @@ class GlobalState(object):
# This is called when it is known that no more global declarations will # This is called when it is known that no more global declarations will
# declared (but can be called before or after insert_XXX). # declared (but can be called before or after insert_XXX).
if self.pystring_table_needed: if self.pystring_table_needed:
self.pystring_table.putln("{0, 0, 0, 0, 0, 0}").putln("};") self.pystring_table.putln("{0, 0, 0, 0, 0, 0}")
self.pystring_table.putln("};")
import Nodes import Nodes
self.use_utility_code(Nodes.init_string_tab_utility_code) self.use_utility_code(Nodes.init_string_tab_utility_code)
self.initwriter.putln( self.initwriter.putln(
...@@ -217,21 +217,19 @@ class GlobalState(object): ...@@ -217,21 +217,19 @@ class GlobalState(object):
self.initwriter.error_goto(self.module_pos))) self.initwriter.error_goto(self.module_pos)))
if Options.cache_builtins: if Options.cache_builtins:
(self.init_cached_builtins_writer w = self.init_cached_builtins_writer
.putln("return 0;") w.putln("return 0;")
.put_label(self.init_cached_builtins_writer.error_label) w.put_label(w.error_label)
.putln("return -1;") w.putln("return -1;")
.putln("}") w.putln("}")
.exit_cfunc_scope() w.exit_cfunc_scope()
)
w = self.initwriter
(self.initwriter w.putln("return 0;")
.putln("return 0;") w.put_label(w.error_label)
.put_label(self.initwriter.error_label) w.putln("return -1;")
.putln("return -1;") w.putln("}")
.putln("}") w.exit_cfunc_scope()
.exit_cfunc_scope()
)
def insert_initcode_into(self, code): def insert_initcode_into(self, code):
if self.pystring_table_needed: if self.pystring_table_needed:
...@@ -526,7 +524,6 @@ class CCodeWriter(object): ...@@ -526,7 +524,6 @@ class CCodeWriter(object):
self.put(code) self.put(code)
self.write("\n"); self.write("\n");
self.bol = 1 self.bol = 1
return self
def emit_marker(self): def emit_marker(self):
self.write("\n"); self.write("\n");
...@@ -534,7 +531,6 @@ class CCodeWriter(object): ...@@ -534,7 +531,6 @@ class CCodeWriter(object):
self.write("/* %s */\n" % self.marker[1]) self.write("/* %s */\n" % self.marker[1])
self.last_marker_line = self.marker[0] self.last_marker_line = self.marker[0]
self.marker = None self.marker = None
return self
def put_safe(self, code): def put_safe(self, code):
# put code, but ignore {} # put code, but ignore {}
...@@ -557,25 +553,20 @@ class CCodeWriter(object): ...@@ -557,25 +553,20 @@ class CCodeWriter(object):
self.level += dl self.level += dl
elif fix_indent: elif fix_indent:
self.level += 1 self.level += 1
return self
def increase_indent(self): def increase_indent(self):
self.level = self.level + 1 self.level = self.level + 1
return self
def decrease_indent(self): def decrease_indent(self):
self.level = self.level - 1 self.level = self.level - 1
return self
def begin_block(self): def begin_block(self):
self.putln("{") self.putln("{")
self.increase_indent() self.increase_indent()
return self
def end_block(self): def end_block(self):
self.decrease_indent() self.decrease_indent()
self.putln("}") self.putln("}")
return self
def indent(self): def indent(self):
self.write(" " * self.level) self.write(" " * self.level)
...@@ -604,12 +595,10 @@ class CCodeWriter(object): ...@@ -604,12 +595,10 @@ class CCodeWriter(object):
def put_label(self, lbl): def put_label(self, lbl):
if lbl in self.funcstate.labels_used: if lbl in self.funcstate.labels_used:
self.putln("%s:;" % lbl) self.putln("%s:;" % lbl)
return self
def put_goto(self, lbl): def put_goto(self, lbl):
self.funcstate.use_label(lbl) self.funcstate.use_label(lbl)
self.putln("goto %s;" % lbl) self.putln("goto %s;" % lbl)
return self
def put_var_declarations(self, entries, static = 0, dll_linkage = None, def put_var_declarations(self, entries, static = 0, dll_linkage = None,
definition = True): definition = True):
......
...@@ -290,6 +290,11 @@ class ExprNode(Node): ...@@ -290,6 +290,11 @@ class ExprNode(Node):
# If this node can be interpreted as a reference to a # If this node can be interpreted as a reference to a
# cimported module, return its scope, else None. # cimported module, return its scope, else None.
return None return None
def analyse_as_type(self, env):
# If this node can be interpreted as a reference to a
# type, return that type, else None.
return None
def analyse_as_extension_type(self, env): def analyse_as_extension_type(self, env):
# If this node can be interpreted as a reference to an # If this node can be interpreted as a reference to an
...@@ -773,6 +778,15 @@ class StringNode(ConstNode): ...@@ -773,6 +778,15 @@ class StringNode(ConstNode):
def analyse_types(self, env): def analyse_types(self, env):
self.entry = env.add_string_const(self.value) self.entry = env.add_string_const(self.value)
def analyse_as_type(self, env):
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)
sizeof_node = declaration.root.stats[0].expr
sizeof_node.analyse_types(env)
if isinstance(sizeof_node, SizeofTypeNode):
return sizeof_node.arg_type
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type.is_int: if dst_type.is_int:
...@@ -944,6 +958,17 @@ class NameNode(AtomicExprNode): ...@@ -944,6 +958,17 @@ class NameNode(AtomicExprNode):
if entry and entry.as_module: if entry and entry.as_module:
return entry.as_module return entry.as_module
return None 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)
entry = self.entry
if not entry:
entry = env.lookup(self.name)
if entry and entry.is_type:
return entry.type
else:
return None
def analyse_as_extension_type(self, env): def analyse_as_extension_type(self, env):
# Try to interpret this as a reference to an extension type. # Try to interpret this as a reference to an extension type.
...@@ -1427,6 +1452,12 @@ class IndexNode(ExprNode): ...@@ -1427,6 +1452,12 @@ class IndexNode(ExprNode):
def analyse_target_declaration(self, env): def analyse_target_declaration(self, env):
pass pass
def analyse_as_type(self, env):
base_type = self.base.analyse_as_type(env)
if base_type and not base_type.is_pyobject:
return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
return None
def analyse_types(self, env): def analyse_types(self, env):
self.analyse_base_and_index_types(env, getting = 1) self.analyse_base_and_index_types(env, getting = 1)
...@@ -2243,6 +2274,14 @@ class AttributeNode(ExprNode): ...@@ -2243,6 +2274,14 @@ class AttributeNode(ExprNode):
self.mutate_into_name_node(env, ubcm_entry, None) self.mutate_into_name_node(env, ubcm_entry, None)
return 1 return 1
return 0 return 0
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 None
def analyse_as_extension_type(self, env): def analyse_as_extension_type(self, env):
# Try to interpret this as a reference to an extension type # Try to interpret this as a reference to an extension type
...@@ -2800,6 +2839,9 @@ class DictItemNode(ExprNode): ...@@ -2800,6 +2839,9 @@ class DictItemNode(ExprNode):
def generate_disposal_code(self, code): def generate_disposal_code(self, code):
self.key.generate_disposal_code(code) self.key.generate_disposal_code(code)
self.value.generate_disposal_code(code) self.value.generate_disposal_code(code)
def __iter__(self):
return iter([self.key, self.value])
class ClassNode(ExprNode): class ClassNode(ExprNode):
...@@ -3168,6 +3210,8 @@ class TypecastNode(ExprNode): ...@@ -3168,6 +3210,8 @@ class TypecastNode(ExprNode):
class SizeofNode(ExprNode): class SizeofNode(ExprNode):
# Abstract base class for sizeof(x) expression nodes. # Abstract base class for sizeof(x) expression nodes.
type = PyrexTypes.c_int_type
def check_const(self): def check_const(self):
pass pass
...@@ -3183,11 +3227,12 @@ class SizeofTypeNode(SizeofNode): ...@@ -3183,11 +3227,12 @@ class SizeofTypeNode(SizeofNode):
# declarator CDeclaratorNode # declarator CDeclaratorNode
subexprs = [] subexprs = []
arg_type = None
def analyse_types(self, env): def analyse_types(self, env):
# we may have incorrectly interpreted a dotted name as a type rather than an attribute # we may have incorrectly interpreted a dotted name as a type rather than an attribute
# this could be better handled by more uniformly treating types as runtime-available objects # this could be better handled by more uniformly treating types as runtime-available objects
if self.base_type.module_path: if 0 and self.base_type.module_path:
path = self.base_type.module_path path = self.base_type.module_path
obj = env.lookup(path[0]) obj = env.lookup(path[0])
if obj.as_module is None: if obj.as_module is None:
...@@ -3199,16 +3244,20 @@ class SizeofTypeNode(SizeofNode): ...@@ -3199,16 +3244,20 @@ class SizeofTypeNode(SizeofNode):
self.__class__ = SizeofVarNode self.__class__ = SizeofVarNode
self.analyse_types(env) self.analyse_types(env)
return return
base_type = self.base_type.analyse(env) if self.arg_type is None:
_, arg_type = self.declarator.analyse(base_type, env) base_type = self.base_type.analyse(env)
self.arg_type = arg_type _, arg_type = self.declarator.analyse(base_type, env)
self.arg_type = arg_type
self.check_type()
def check_type(self):
arg_type = self.arg_type
if arg_type.is_pyobject and not arg_type.is_extension_type: if arg_type.is_pyobject and not arg_type.is_extension_type:
error(self.pos, "Cannot take sizeof Python object") error(self.pos, "Cannot take sizeof Python object")
elif arg_type.is_void: elif arg_type.is_void:
error(self.pos, "Cannot take sizeof void") error(self.pos, "Cannot take sizeof void")
elif not arg_type.is_complete(): elif not arg_type.is_complete():
error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type) error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
self.type = PyrexTypes.c_int_type
def calculate_result_code(self): def calculate_result_code(self):
if self.arg_type.is_extension_type: if self.arg_type.is_extension_type:
...@@ -3228,8 +3277,15 @@ class SizeofVarNode(SizeofNode): ...@@ -3228,8 +3277,15 @@ class SizeofVarNode(SizeofNode):
subexprs = ['operand'] subexprs = ['operand']
def analyse_types(self, env): def analyse_types(self, env):
self.operand.analyse_types(env) # We may actually be looking at a type rather than a variable...
self.type = PyrexTypes.c_int_type # If we are, traditional analysis would fail...
operand_as_type = self.operand.analyse_as_type(env)
if operand_as_type:
self.arg_type = operand_as_type
self.__class__ = SizeofTypeNode
self.check_type()
else:
self.operand.analyse_types(env)
def calculate_result_code(self): def calculate_result_code(self):
return "(sizeof(%s))" % self.operand.result() return "(sizeof(%s))" % self.operand.result()
...@@ -3475,22 +3531,27 @@ class FloorDivNode(NumBinopNode): ...@@ -3475,22 +3531,27 @@ class FloorDivNode(NumBinopNode):
self.operand2.result()) self.operand2.result())
class ModNode(IntBinopNode): class ModNode(NumBinopNode):
# '%' operator. # '%' operator.
def is_py_operation(self): def is_py_operation(self):
return (self.operand1.type.is_string return (self.operand1.type.is_string
or self.operand2.type.is_string or self.operand2.type.is_string
or IntBinopNode.is_py_operation(self)) or NumBinopNode.is_py_operation(self))
def calculate_result_code(self):
if self.operand1.type.is_float or self.operand2.type.is_float:
return "fmod(%s, %s)" % (
self.operand1.result(),
self.operand2.result())
else:
return "(%s %% %s)" % (
self.operand1.result(),
self.operand2.result())
class PowNode(NumBinopNode): class PowNode(NumBinopNode):
# '**' operator. # '**' operator.
def analyse_types(self, env):
env.pow_function_used = 1
NumBinopNode.analyse_types(self, env)
def compute_c_result_type(self, type1, type2): def compute_c_result_type(self, type1, type2):
if self.c_types_okay(type1, type2): if self.c_types_okay(type1, type2):
return PyrexTypes.c_double_type return PyrexTypes.c_double_type
......
...@@ -79,7 +79,7 @@ class Context: ...@@ -79,7 +79,7 @@ class Context:
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 from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
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
...@@ -97,11 +97,12 @@ class Context: ...@@ -97,11 +97,12 @@ class Context:
PostParse(self), PostParse(self),
_specific_post_parse, _specific_post_parse,
InterpretCompilerDirectives(self, self.pragma_overrides), InterpretCompilerDirectives(self, self.pragma_overrides),
EmbedSignature(self),
FlattenInListTransform(), FlattenInListTransform(),
WithTransform(self), WithTransform(self),
DecoratorTransform(self), DecoratorTransform(self),
AnalyseDeclarationsTransform(self), AnalyseDeclarationsTransform(self),
EmbedSignature(self),
TransformBuiltinMethods(self),
IntroduceBufferAuxiliaryVars(self), IntroduceBufferAuxiliaryVars(self),
_check_c_classes, _check_c_classes,
AnalyseExpressionsTransform(self), AnalyseExpressionsTransform(self),
......
...@@ -411,8 +411,10 @@ class CNameDeclaratorNode(CDeclaratorNode): ...@@ -411,8 +411,10 @@ class CNameDeclaratorNode(CDeclaratorNode):
error(self.pos, "Missing argument name") error(self.pos, "Missing argument name")
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.")
self.name = base_type.declaration_code("", for_display=1, pyrex=1) else:
base_type = py_object_type print "here"
self.name = base_type.declaration_code("", for_display=1, pyrex=1)
base_type = py_object_type
self.type = base_type self.type = base_type
return self, base_type return self, base_type
...@@ -570,7 +572,19 @@ class CArgDeclNode(Node): ...@@ -570,7 +572,19 @@ class CArgDeclNode(Node):
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 ###
base_type = self.base_type.analyse(env) # The parser may missinterpret names as types...
# We fix that here.
if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
if nonempty:
self.declarator.name = self.base_type.name
self.base_type.name = None
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) return self.declarator.analyse(base_type, env, nonempty = nonempty)
def annotate(self, code): def annotate(self, code):
...@@ -597,8 +611,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -597,8 +611,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
# is_self_arg boolean Is self argument of C method # is_self_arg boolean Is self argument of C method
child_attrs = [] child_attrs = []
arg_name = None # in case the argument name was interpreted as a type
def analyse(self, env): def analyse(self, env, could_be_name = False):
# Return type descriptor. # Return type descriptor.
#print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ### #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
type = None type = None
...@@ -615,13 +630,22 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -615,13 +630,22 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else: else:
type = py_object_type type = py_object_type
else: else:
scope = env.find_imported_module(self.module_path, self.pos) if self.module_path:
scope = env.find_imported_module(self.module_path, self.pos)
else:
scope = env
if scope: if scope:
if scope.is_c_class_scope: if scope.is_c_class_scope:
scope = scope.global_scope() scope = scope.global_scope()
entry = scope.find(self.name, self.pos) entry = scope.lookup(self.name)
if entry and entry.is_type: if entry and entry.is_type:
type = entry.type type = entry.type
elif could_be_name:
if self.is_self_arg and env.is_c_class_scope:
type = env.parent_type
else:
type = py_object_type
self.arg_name = self.name
else: else:
error(self.pos, "'%s' is not a type identifier" % self.name) error(self.pos, "'%s' is not a type identifier" % self.name)
if type: if type:
...@@ -644,7 +668,7 @@ class CBufferAccessTypeNode(CBaseTypeNode): ...@@ -644,7 +668,7 @@ class CBufferAccessTypeNode(CBaseTypeNode):
dtype_node = None dtype_node = None
def analyse(self, env): def analyse(self, env, could_be_name = False):
base_type = self.base_type_node.analyse(env) base_type = self.base_type_node.analyse(env)
if base_type.is_error: return base_type if base_type.is_error: return base_type
import Buffer import Buffer
...@@ -665,8 +689,8 @@ class CComplexBaseTypeNode(CBaseTypeNode): ...@@ -665,8 +689,8 @@ class CComplexBaseTypeNode(CBaseTypeNode):
child_attrs = ["base_type", "declarator"] child_attrs = ["base_type", "declarator"]
def analyse(self, env): def analyse(self, env, could_be_name = False):
base = self.base_type.analyse(env) base = self.base_type.analyse(env, could_be_name)
_, type = self.declarator.analyse(base, env) _, type = self.declarator.analyse(base, env)
return type return type
...@@ -1142,11 +1166,16 @@ class CFuncDefNode(FuncDefNode): ...@@ -1142,11 +1166,16 @@ class CFuncDefNode(FuncDefNode):
# overridable whether or not this is a cpdef function # overridable whether or not this is a cpdef function
child_attrs = ["base_type", "declarator", "body", "py_func"] child_attrs = ["base_type", "declarator", "body", "py_func"]
def unqualified_name(self): def unqualified_name(self):
return self.entry.name return self.entry.name
def analyse_declarations(self, env): def analyse_declarations(self, env):
if 'locals' in env.directives:
directive_locals = env.directives['locals']
else:
directive_locals = {}
self.directive_locals = directive_locals
base_type = self.base_type.analyse(env) base_type = self.base_type.analyse(env)
# The 2 here is because we need both function and argument names. # 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)) name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
...@@ -1418,11 +1447,27 @@ class DefNode(FuncDefNode): ...@@ -1418,11 +1447,27 @@ class DefNode(FuncDefNode):
entry = None entry = None
def analyse_declarations(self, env): def analyse_declarations(self, env):
if 'locals' in env.directives:
directive_locals = env.directives['locals']
else:
directive_locals = {}
self.directive_locals = directive_locals
for arg in self.args: for arg in self.args:
base_type = arg.base_type.analyse(env) base_type = arg.base_type.analyse(env)
name_declarator, type = \ name_declarator, type = \
arg.declarator.analyse(base_type, env) arg.declarator.analyse(base_type, env)
arg.name = name_declarator.name arg.name = name_declarator.name
if arg.name in directive_locals:
type_node = directive_locals[arg.name]
other_type = type_node.analyse_as_type(env)
if other_type is None:
error(type_node.pos, "Not a type")
elif (type is not PyrexTypes.py_object_type
and not type.same_as(other_type)):
error(arg.base_type.pos, "Signature does not agree with previous declaration")
error(type_node.pos, "Previous declaration here")
else:
type = other_type
if name_declarator.cname: if name_declarator.cname:
error(self.pos, error(self.pos,
"Python function argument cannot have C name specification") "Python function argument cannot have C name specification")
......
...@@ -58,13 +58,15 @@ c_line_in_traceback = 1 ...@@ -58,13 +58,15 @@ c_line_in_traceback = 1
option_types = { option_types = {
'boundscheck' : bool, 'boundscheck' : bool,
'nonecheck' : bool, 'nonecheck' : bool,
'embedsignature' : bool 'embedsignature' : bool,
'locals' : dict,
} }
option_defaults = { option_defaults = {
'boundscheck' : True, 'boundscheck' : True,
'nonecheck' : False, 'nonecheck' : False,
'embedsignature' : False, 'embedsignature' : False,
'locals' : {}
} }
def parse_option_value(name, value): def parse_option_value(name, value):
......
...@@ -282,6 +282,7 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -282,6 +282,7 @@ class InterpretCompilerDirectives(CythonTransform):
self.options = options self.options = options
node.directives = options node.directives = options
self.visitchildren(node) self.visitchildren(node)
node.cython_module_names = self.cython_module_names
return node return node
# Track cimports of the cython module. # Track cimports of the cython module.
...@@ -308,6 +309,14 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -308,6 +309,14 @@ class InterpretCompilerDirectives(CythonTransform):
newimp.append((pos, name, as_name, kind)) newimp.append((pos, name, as_name, kind))
node.imported_names = newimpo node.imported_names = newimpo
return node return node
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)
else:
self.visitchildren(node)
return node
def visit_Node(self, node): def visit_Node(self, node):
self.visitchildren(node) self.visitchildren(node)
...@@ -318,7 +327,7 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -318,7 +327,7 @@ class InterpretCompilerDirectives(CythonTransform):
# decorator), returns (optionname, value). # decorator), returns (optionname, value).
# Otherwise, returns None # Otherwise, returns None
optname = None optname = None
if isinstance(node, SimpleCallNode): if isinstance(node, CallNode):
if (isinstance(node.function, AttributeNode) and if (isinstance(node.function, AttributeNode) and
isinstance(node.function.obj, NameNode) and isinstance(node.function.obj, NameNode) and
node.function.obj.name in self.cython_module_names): node.function.obj.name in self.cython_module_names):
...@@ -330,12 +339,25 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -330,12 +339,25 @@ class InterpretCompilerDirectives(CythonTransform):
if optname: if optname:
optiontype = Options.option_types.get(optname) optiontype = Options.option_types.get(optname)
if optiontype: if optiontype:
args = node.args 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
if optiontype is bool: if optiontype is bool:
if 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,
'The %s option takes one compile-time boolean argument' % optname) 'The %s option takes one compile-time boolean argument' % optname)
return (optname, args[0].value) return (optname, args[0].value)
elif optiontype is dict:
if len(args) != 0:
raise PostParseError(dec.function.pos,
'The %s option takes no prepositional arguments' % optname)
return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
else: else:
assert False assert False
...@@ -367,7 +389,7 @@ class InterpretCompilerDirectives(CythonTransform): ...@@ -367,7 +389,7 @@ class InterpretCompilerDirectives(CythonTransform):
else: else:
realdecs.append(dec) realdecs.append(dec)
node.decorators = realdecs node.decorators = realdecs
if options: if options:
optdict = {} optdict = {}
options.reverse() # Decorators coming first take precedence options.reverse() # Decorators coming first take precedence
...@@ -499,12 +521,19 @@ property NAME: ...@@ -499,12 +521,19 @@ property NAME:
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
node.declare_arguments(lenv) node.declare_arguments(lenv)
for var, type_node in node.directive_locals.items():
if not lenv.lookup_here(var): # don't redeclare args
type = type_node.analyse_as_type(lenv)
if type:
lenv.declare_var(var, type, type_node.pos)
else:
error(type_node.pos, "Not a type")
node.body.analyse_declarations(lenv) node.body.analyse_declarations(lenv)
self.env_stack.append(lenv) self.env_stack.append(lenv)
self.visitchildren(node) self.visitchildren(node)
self.env_stack.pop() self.env_stack.pop()
return node return node
# Some nodes are no longer needed after declaration # Some nodes are no longer needed after declaration
# analysis and can be dropped. The analysis was performed # analysis and can be dropped. The analysis was performed
# on these nodes in a seperate recursive process from the # on these nodes in a seperate recursive process from the
...@@ -534,6 +563,7 @@ property NAME: ...@@ -534,6 +563,7 @@ property NAME:
return property return property
class AnalyseExpressionsTransform(CythonTransform): class AnalyseExpressionsTransform(CythonTransform):
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
node.body.analyse_expressions(node.scope) node.body.analyse_expressions(node.scope)
self.visitchildren(node) self.visitchildren(node)
...@@ -591,3 +621,78 @@ class CreateClosureClasses(CythonTransform): ...@@ -591,3 +621,78 @@ class CreateClosureClasses(CythonTransform):
return node return node
class EnvTransform(CythonTransform):
"""
This transformation keeps a stack of the environments.
"""
def __call__(self, root):
self.env_stack = [root.scope]
return super(EnvTransform, self).__call__(root)
def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope)
self.visitchildren(node)
self.env_stack.pop()
return node
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
self.visitchildren(node)
return node
def visit_AttributeNode(self, node):
attribute = self.cython_attribute(node)
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)
return node
def visit_SimpleCallNode(self, node):
# locals
if isinstance(node.function, ExprNodes.NameNode):
if node.function.name == 'locals':
pos = node.pos
lenv = self.env_stack[-1]
items = [ExprNodes.DictItemNode(pos,
key=ExprNodes.IdentifierStringNode(pos, value=var),
value=ExprNodes.NameNode(pos, name=var)) for var in lenv.entries]
return ExprNodes.DictNode(pos, key_value_pairs=items)
# cython.foo
function = self.cython_attribute(node.function)
if function:
if function == u'cast':
if len(node.args) != 2:
error(node.function.pos, u"cast takes exactly two arguments" % function)
else:
type = node.args[0].analyse_as_type(self.env_stack[-1])
if type:
node = TypecastNode(node.function.pos, type=type, operand=node.args[1])
else:
error(node.args[0].pos, "Not a type")
elif function == u'sizeof':
if len(node.args) != 1:
error(node.function.pos, u"sizeof takes exactly one argument" % function)
else:
type = node.args[0].analyse_as_type(self.env_stack[-1])
if type:
node = SizeofTypeNode(node.function.pos, arg_type=type)
else:
node = SizeofVarNode(node.function.pos, operand=node.args[0])
else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function)
self.visitchildren(node)
return node
...@@ -250,14 +250,17 @@ def p_sizeof(s): ...@@ -250,14 +250,17 @@ def p_sizeof(s):
pos = s.position() pos = s.position()
s.next() s.next()
s.expect('(') s.expect('(')
if looking_at_type(s) or looking_at_dotted_name(s): # Here we decide if we are looking at an expression or type
# If it is actually a type, but parsable as an expression,
# we treat it as an expression here.
if looking_at_expr(s):
operand = p_simple_expr(s)
node = ExprNodes.SizeofVarNode(pos, operand = operand)
else:
base_type = p_c_base_type(s) base_type = p_c_base_type(s)
declarator = p_c_declarator(s, empty = 1) declarator = p_c_declarator(s, empty = 1)
node = ExprNodes.SizeofTypeNode(pos, node = ExprNodes.SizeofTypeNode(pos,
base_type = base_type, declarator = declarator) base_type = base_type, declarator = declarator)
else:
operand = p_simple_expr(s)
node = ExprNodes.SizeofVarNode(pos, operand = operand)
s.expect(')') s.expect(')')
return node return node
...@@ -1028,9 +1031,6 @@ def p_from_import_statement(s, first_statement = 0): ...@@ -1028,9 +1031,6 @@ def p_from_import_statement(s, first_statement = 0):
s.context.future_directives.add(directive) s.context.future_directives.add(directive)
return Nodes.PassStatNode(pos) return Nodes.PassStatNode(pos)
elif kind == 'cimport': elif kind == 'cimport':
for (name_pos, name, as_name, kind) in imported_names:
local_name = as_name or name
s.add_type_name(local_name)
return Nodes.FromCImportStatNode(pos, return Nodes.FromCImportStatNode(pos,
module_name = dotted_name, module_name = dotted_name,
imported_names = imported_names) imported_names = imported_names)
...@@ -1604,7 +1604,7 @@ def p_c_complex_base_type(s): ...@@ -1604,7 +1604,7 @@ def p_c_complex_base_type(s):
base_type = base_type, declarator = declarator) base_type = base_type, declarator = declarator)
def p_c_simple_base_type(s, self_flag, nonempty): def p_c_simple_base_type(s, self_flag, nonempty):
#print "p_c_simple_base_type: self_flag =", self_flag #print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0 is_basic = 0
signed = 1 signed = 1
longness = 0 longness = 0
...@@ -1619,12 +1619,19 @@ def p_c_simple_base_type(s, self_flag, nonempty): ...@@ -1619,12 +1619,19 @@ def p_c_simple_base_type(s, self_flag, nonempty):
s.next() s.next()
else: else:
name = 'int' name = 'int'
elif s.looking_at_type_name(): elif looking_at_dotted_name(s):
#print "p_c_simple_base_type: looking_at_type_name at", s.position()
name = s.systring
s.next()
while s.sy == '.':
module_path.append(name)
s.next()
name = p_ident(s)
else:
name = s.systring name = s.systring
s.next() s.next()
if nonempty and s.sy != 'IDENT': if nonempty and s.sy != 'IDENT':
# Make sure this is not a declaration of a variable or # Make sure this is not a declaration of a variable or function.
# function with the same name as a type.
if s.sy == '(': if s.sy == '(':
s.next() s.next()
if s.sy == '*' or s.sy == '**': if s.sy == '*' or s.sy == '**':
...@@ -1636,18 +1643,7 @@ def p_c_simple_base_type(s, self_flag, nonempty): ...@@ -1636,18 +1643,7 @@ def p_c_simple_base_type(s, self_flag, nonempty):
elif s.sy not in ('*', '**', '['): elif s.sy not in ('*', '**', '['):
s.put_back('IDENT', name) s.put_back('IDENT', name)
name = None name = None
elif looking_at_dotted_name(s):
#print "p_c_simple_base_type: looking_at_type_name at", s.position()
name = s.systring
s.next()
while s.sy == '.':
module_path.append(name)
s.next()
name = p_ident(s)
else:
#print "p_c_simple_base_type: not looking at type at", s.position()
name = None
type_node = Nodes.CSimpleBaseTypeNode(pos, type_node = Nodes.CSimpleBaseTypeNode(pos,
name = name, module_path = module_path, name = name, module_path = module_path,
is_basic_c_type = is_basic, signed = signed, is_basic_c_type = is_basic, signed = signed,
...@@ -1687,8 +1683,44 @@ def p_buffer_access(s, base_type_node): ...@@ -1687,8 +1683,44 @@ def p_buffer_access(s, base_type_node):
return result return result
def looking_at_type(s): def looking_at_name(s):
return looking_at_base_type(s) or s.looking_at_type_name() return s.sy == 'IDENT' and not s.systring in calling_convention_words
def looking_at_expr(s):
if s.systring in base_type_start_words:
return False
elif s.sy == 'IDENT':
is_type = False
name = s.systring
dotted_path = []
s.next()
while s.sy == '.':
s.next()
dotted_path.append(s.systring)
s.expect('IDENT')
saved = s.sy, s.systring
if s.sy == 'IDENT':
is_type = True
elif s.sy == '*' or s.sy == '**':
s.next()
is_type = s.sy == ')'
s.put_back(*saved)
elif s.sy == '(':
s.next()
is_type = s.sy == '*'
s.put_back(*saved)
elif s.sy == '[':
s.next()
is_type = s.sy == ']'
s.put_back(*saved)
dotted_path.reverse()
for p in dotted_path:
s.put_back('IDENT', p)
s.put_back('.', '.')
s.put_back('IDENT', name)
return not is_type
else:
return True
def looking_at_base_type(s): def looking_at_base_type(s):
#print "looking_at_base_type?", s.sy, s.systring, s.position() #print "looking_at_base_type?", s.sy, s.systring, s.position()
...@@ -1703,7 +1735,7 @@ def looking_at_dotted_name(s): ...@@ -1703,7 +1735,7 @@ def looking_at_dotted_name(s):
return result return result
else: else:
return 0 return 0
basic_c_type_names = ("void", "char", "int", "float", "double", "Py_ssize_t", "bint") basic_c_type_names = ("void", "char", "int", "float", "double", "Py_ssize_t", "bint")
sign_and_longness_words = ("short", "long", "signed", "unsigned") sign_and_longness_words = ("short", "long", "signed", "unsigned")
...@@ -1744,7 +1776,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0, ...@@ -1744,7 +1776,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0,
pos = s.position() pos = s.position()
if s.sy == '(': if s.sy == '(':
s.next() s.next()
if s.sy == ')' or looking_at_type(s): if s.sy == ')' or looking_at_name(s):
base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(u""), cname = None) base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(u""), cname = None)
result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag) result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag)
else: else:
...@@ -1816,8 +1848,6 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag, ...@@ -1816,8 +1848,6 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
rhs = None rhs = None
if s.sy == 'IDENT': if s.sy == 'IDENT':
name = EncodedString(s.systring) name = EncodedString(s.systring)
if is_type:
s.add_type_name(name)
if empty: if empty:
error(s.position(), "Declarator should be empty") error(s.position(), "Declarator should be empty")
s.next() s.next()
...@@ -2002,7 +2032,6 @@ def p_c_enum_definition(s, pos, ctx): ...@@ -2002,7 +2032,6 @@ def p_c_enum_definition(s, pos, ctx):
if s.sy == 'IDENT': if s.sy == 'IDENT':
name = s.systring name = s.systring
s.next() s.next()
s.add_type_name(name)
cname = p_opt_cname(s) cname = p_opt_cname(s)
else: else:
name = None name = None
...@@ -2052,7 +2081,6 @@ def p_c_struct_or_union_definition(s, pos, ctx): ...@@ -2052,7 +2081,6 @@ def p_c_struct_or_union_definition(s, pos, ctx):
s.next() s.next()
name = p_ident(s) name = p_ident(s)
cname = p_opt_cname(s) cname = p_opt_cname(s)
s.add_type_name(name)
attributes = None attributes = None
if s.sy == ':': if s.sy == ':':
s.next() s.next()
...@@ -2149,6 +2177,8 @@ def p_ctypedef_statement(s, ctx): ...@@ -2149,6 +2177,8 @@ def p_ctypedef_statement(s, ctx):
return p_c_struct_or_union_definition(s, pos, ctx) return p_c_struct_or_union_definition(s, pos, ctx)
else: else:
base_type = p_c_base_type(s, nonempty = 1) base_type = p_c_base_type(s, nonempty = 1)
if base_type.name is None:
s.error("Syntax error in ctypedef statement")
declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1) declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1)
s.expect_newline("Syntax error in ctypedef statement") s.expect_newline("Syntax error in ctypedef statement")
return Nodes.CTypeDefNode( return Nodes.CTypeDefNode(
...@@ -2244,7 +2274,6 @@ def p_c_class_definition(s, pos, ctx): ...@@ -2244,7 +2274,6 @@ def p_c_class_definition(s, pos, ctx):
as_name = p_ident(s) as_name = p_ident(s)
else: else:
as_name = class_name as_name = class_name
s.add_type_name(as_name)
objstruct_name = None objstruct_name = None
typeobj_name = None typeobj_name = None
base_class_module = None base_class_module = None
...@@ -2345,8 +2374,6 @@ def p_doc_string(s): ...@@ -2345,8 +2374,6 @@ def p_doc_string(s):
return None return None
def p_code(s, level=None): def p_code(s, level=None):
s.add_type_name("object")
s.add_type_name("Py_buffer")
body = p_statement_list(s, Ctx(level = level), first_statement = 1) body = p_statement_list(s, Ctx(level = level), first_statement = 1)
if s.sy != 'EOF': if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % ( s.error("Syntax error in statement [%s,%s]" % (
...@@ -2371,8 +2398,6 @@ def p_compiler_directive_comments(s): ...@@ -2371,8 +2398,6 @@ def p_compiler_directive_comments(s):
return result return result
def p_module(s, pxd, full_module_name): def p_module(s, pxd, full_module_name):
s.add_type_name("object")
s.add_type_name("Py_buffer")
pos = s.position() pos = s.position()
doc = p_doc_string(s) doc = p_doc_string(s)
if pxd: if pxd:
......
...@@ -280,7 +280,6 @@ class BuiltinObjectType(PyObjectType): ...@@ -280,7 +280,6 @@ class BuiltinObjectType(PyObjectType):
return "<%s>"% self.cname return "<%s>"% self.cname
def assignable_from(self, src_type): def assignable_from(self, src_type):
if isinstance(src_type, BuiltinObjectType): if isinstance(src_type, BuiltinObjectType):
return src_type.name == self.name return src_type.name == self.name
else: else:
...@@ -473,6 +472,8 @@ class CNumericType(CType): ...@@ -473,6 +472,8 @@ class CNumericType(CType):
def declaration_code(self, entity_code, def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0): for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl(self.sign_and_name(), dll_linkage) base = public_decl(self.sign_and_name(), dll_linkage)
if for_display and self.is_longlong:
base = base.replace('PY_LONG_LONG', 'long long')
return self.base_declaration_code(base, entity_code) return self.base_declaration_code(base, entity_code)
...@@ -557,7 +558,7 @@ class CULongType(CUIntType): ...@@ -557,7 +558,7 @@ class CULongType(CUIntType):
from_py_function = "PyInt_AsUnsignedLongMask" from_py_function = "PyInt_AsUnsignedLongMask"
class CLongLongType(CUIntType): class CLongLongType(CIntType):
is_longlong = 1 is_longlong = 1
to_py_function = "PyLong_FromLongLong" to_py_function = "PyLong_FromLongLong"
...@@ -1184,6 +1185,9 @@ modifiers_and_name_to_type = { ...@@ -1184,6 +1185,9 @@ modifiers_and_name_to_type = {
(2, 1, "int"): c_slong_type, (2, 1, "int"): c_slong_type,
(2, 2, "int"): c_slonglong_type, (2, 2, "int"): c_slonglong_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, "bint"): c_bint_type,
} }
def widest_numeric_type(type1, type2): def widest_numeric_type(type1, type2):
...@@ -1220,6 +1224,19 @@ def c_ptr_type(base_type): ...@@ -1220,6 +1224,19 @@ def c_ptr_type(base_type):
return c_char_ptr_type return c_char_ptr_type
else: else:
return CPtrType(base_type) return CPtrType(base_type)
def Node_to_type(node, env):
from ExprNodes import NameNode, AttributeNode, StringNode, error
if isinstance(node, StringNode):
node = NameNode(node.pos, name=node.value)
if isinstance(node, NameNode) and node.name in rank_to_type_name:
return simple_c_type(1, 0, node.name)
elif isinstance(node, (AttributeNode, NameNode)):
node.analyze_types(env)
if not node.entry.is_type:
pass
else:
error(node.pos, "Bad type")
def public_decl(base, dll_linkage): def public_decl(base, dll_linkage):
if dll_linkage: if dll_linkage:
......
...@@ -282,7 +282,6 @@ class StringSourceDescriptor(SourceDescriptor): ...@@ -282,7 +282,6 @@ class StringSourceDescriptor(SourceDescriptor):
class PyrexScanner(Scanner): class PyrexScanner(Scanner):
# context Context Compilation context # context Context Compilation context
# type_names set Identifiers to be treated as type names
# included_files [string] Files included with 'include' statement # included_files [string] Files included with 'include' statement
# compile_time_env dict Environment for conditional compilation # compile_time_env dict Environment for conditional compilation
# compile_time_eval boolean In a true conditional compilation context # compile_time_eval boolean In a true conditional compilation context
...@@ -290,18 +289,16 @@ class PyrexScanner(Scanner): ...@@ -290,18 +289,16 @@ class PyrexScanner(Scanner):
resword_dict = build_resword_dict() resword_dict = build_resword_dict()
def __init__(self, file, filename, parent_scanner = None, def __init__(self, file, filename, parent_scanner = None,
scope = None, context = None, source_encoding=None, parse_comments=True): scope = None, context = None, source_encoding=None, parse_comments=True, initial_pos=None):
Scanner.__init__(self, get_lexicon(), file, filename) Scanner.__init__(self, get_lexicon(), file, filename, initial_pos)
if parent_scanner: if parent_scanner:
self.context = parent_scanner.context self.context = parent_scanner.context
self.type_names = parent_scanner.type_names
self.included_files = parent_scanner.included_files self.included_files = parent_scanner.included_files
self.compile_time_env = parent_scanner.compile_time_env self.compile_time_env = parent_scanner.compile_time_env
self.compile_time_eval = parent_scanner.compile_time_eval self.compile_time_eval = parent_scanner.compile_time_eval
self.compile_time_expr = parent_scanner.compile_time_expr self.compile_time_expr = parent_scanner.compile_time_expr
else: else:
self.context = context self.context = context
self.type_names = scope.type_names
self.included_files = scope.included_files self.included_files = scope.included_files
self.compile_time_env = initial_compile_time_env() self.compile_time_env = initial_compile_time_env()
self.compile_time_eval = 1 self.compile_time_eval = 1
...@@ -431,12 +428,6 @@ class PyrexScanner(Scanner): ...@@ -431,12 +428,6 @@ class PyrexScanner(Scanner):
# This method should be added to Plex # This method should be added to Plex
self.queue.insert(0, (token, value)) self.queue.insert(0, (token, value))
def add_type_name(self, name):
self.type_names[name] = 1
def looking_at_type_name(self):
return self.sy == 'IDENT' and self.systring in self.type_names
def error(self, message, pos = None, fatal = True): def error(self, message, pos = None, fatal = True):
if pos is None: if pos is None:
pos = self.position() pos = self.position()
......
...@@ -167,7 +167,6 @@ class Scope: ...@@ -167,7 +167,6 @@ class Scope:
# temp_counter integer Counter for naming temp vars # temp_counter integer Counter for naming temp vars
# cname_to_entry {string : Entry} Temp cname to entry mapping # cname_to_entry {string : Entry} Temp cname to entry mapping
# int_to_entry {int : Entry} Temp cname to entry mapping # int_to_entry {int : Entry} Temp cname to entry mapping
# pow_function_used boolean The C pow() function is used
# return_type PyrexType or None Return type of function owning scope # return_type PyrexType or None Return type of function owning scope
# is_py_class_scope boolean Is a Python class scope # is_py_class_scope boolean Is a Python class scope
# is_c_class_scope boolean Is an extension type scope # is_c_class_scope boolean Is an extension type scope
...@@ -221,7 +220,6 @@ class Scope: ...@@ -221,7 +220,6 @@ class Scope:
#self.pending_temp_entries = [] # TEMPORARY #self.pending_temp_entries = [] # TEMPORARY
self.temp_counter = 1 self.temp_counter = 1
self.cname_to_entry = {} self.cname_to_entry = {}
self.pow_function_used = 0
self.string_to_entry = {} self.string_to_entry = {}
self.identifier_to_entry = {} self.identifier_to_entry = {}
self.num_to_entry = {} self.num_to_entry = {}
...@@ -315,6 +313,7 @@ class Scope: ...@@ -315,6 +313,7 @@ class Scope:
entry.is_type = 1 entry.is_type = 1
if defining: if defining:
self.type_entries.append(entry) self.type_entries.append(entry)
# here we would set as_variable to an object representing this type
return entry return entry
def declare_typedef(self, name, base_type, pos, cname = None, def declare_typedef(self, name, base_type, pos, cname = None,
...@@ -637,8 +636,6 @@ class Scope: ...@@ -637,8 +636,6 @@ class Scope:
def generate_library_function_declarations(self, code): def generate_library_function_declarations(self, code):
# Generate extern decls for C library funcs used. # Generate extern decls for C library funcs used.
#if self.pow_function_used:
# code.putln("%s double pow(double, double);" % Naming.extern_c_macro)
pass pass
def defines_any(self, names): def defines_any(self, names):
...@@ -722,21 +719,27 @@ class BuiltinScope(Scope): ...@@ -722,21 +719,27 @@ class BuiltinScope(Scope):
def builtin_scope(self): def builtin_scope(self):
return self return self
builtin_entries = { builtin_entries = {
"type": ["((PyObject*)&PyType_Type)", py_object_type],
"bool": ["((PyObject*)&PyBool_Type)", py_object_type],
"int": ["((PyObject*)&PyInt_Type)", py_object_type], "int": ["((PyObject*)&PyInt_Type)", py_object_type],
"long": ["((PyObject*)&PyLong_Type)", py_object_type], "long": ["((PyObject*)&PyLong_Type)", py_object_type],
"float": ["((PyObject*)&PyFloat_Type)", py_object_type], "float": ["((PyObject*)&PyFloat_Type)", py_object_type],
"complex":["((PyObject*)&PyComplex_Type)", py_object_type],
"str": ["((PyObject*)&PyBytes_Type)", py_object_type],
"bytes": ["((PyObject*)&PyBytes_Type)", py_object_type],
"str": ["((PyObject*)&PyString_Type)", py_object_type],
"unicode":["((PyObject*)&PyUnicode_Type)", py_object_type], "unicode":["((PyObject*)&PyUnicode_Type)", py_object_type],
"tuple": ["((PyObject*)&PyTuple_Type)", py_object_type], "tuple": ["((PyObject*)&PyTuple_Type)", py_object_type],
"list": ["((PyObject*)&PyList_Type)", py_object_type], "list": ["((PyObject*)&PyList_Type)", py_object_type],
"dict": ["((PyObject*)&PyDict_Type)", py_object_type], "dict": ["((PyObject*)&PyDict_Type)", py_object_type],
"set": ["((PyObject*)&PySet_Type)", py_object_type], "set": ["((PyObject*)&PySet_Type)", py_object_type],
"frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type], "frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type],
"type": ["((PyObject*)&PyType_Type)", py_object_type],
"slice": ["((PyObject*)&PySlice_Type)", py_object_type], "slice": ["((PyObject*)&PySlice_Type)", py_object_type],
"file": ["((PyObject*)&PyFile_Type)", py_object_type], "file": ["((PyObject*)&PyFile_Type)", py_object_type],
......
...@@ -29,7 +29,7 @@ class StringParseContext(Main.Context): ...@@ -29,7 +29,7 @@ class StringParseContext(Main.Context):
raise AssertionError("Not yet supporting any cimports/includes from string code snippets") raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
return ModuleScope(module_name, parent_module = None, context = self) return ModuleScope(module_name, parent_module = None, context = self)
def parse_from_strings(name, code, pxds={}, level=None): def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None):
""" """
Utility method to parse a (unicode) string of code. This is mostly Utility method to parse a (unicode) string of code. This is mostly
used for internal Cython compiler purposes (creating code snippets used for internal Cython compiler purposes (creating code snippets
...@@ -47,7 +47,8 @@ def parse_from_strings(name, code, pxds={}, level=None): ...@@ -47,7 +47,8 @@ def parse_from_strings(name, code, pxds={}, level=None):
encoding = "UTF-8" encoding = "UTF-8"
module_name = name module_name = name
initial_pos = (name, 1, 0) if initial_pos is None:
initial_pos = (name, 1, 0)
code_source = StringSourceDescriptor(name, code) code_source = StringSourceDescriptor(name, code)
context = StringParseContext([], name) context = StringParseContext([], name)
...@@ -56,7 +57,7 @@ def parse_from_strings(name, code, pxds={}, level=None): ...@@ -56,7 +57,7 @@ def parse_from_strings(name, code, pxds={}, level=None):
buf = StringIO(code.encode(encoding)) buf = StringIO(code.encode(encoding))
scanner = PyrexScanner(buf, code_source, source_encoding = encoding, scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
scope = scope, context = context) scope = scope, context = context, initial_pos = initial_pos)
if level is None: if level is None:
tree = Parsing.p_module(scanner, 0, module_name) tree = Parsing.p_module(scanner, 0, module_name)
else: else:
...@@ -181,7 +182,7 @@ def strip_common_indent(lines): ...@@ -181,7 +182,7 @@ def strip_common_indent(lines):
return lines return lines
class TreeFragment(object): class TreeFragment(object):
def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None): def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None, initial_pos=None):
if isinstance(code, unicode): if isinstance(code, unicode):
def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n"))) def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))
...@@ -189,8 +190,7 @@ class TreeFragment(object): ...@@ -189,8 +190,7 @@ class TreeFragment(object):
fmt_pxds = {} fmt_pxds = {}
for key, value in pxds.iteritems(): for key, value in pxds.iteritems():
fmt_pxds[key] = fmt(value) fmt_pxds[key] = fmt(value)
mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos)
mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level)
if level is None: if level is None:
t = t.body # Make sure a StatListNode is at the top t = t.body # Make sure a StatListNode is at the top
if not isinstance(t, StatListNode): if not isinstance(t, StatListNode):
......
...@@ -60,7 +60,7 @@ class Scanner: ...@@ -60,7 +60,7 @@ class Scanner:
queue = None # list of tokens to be returned queue = None # list of tokens to be returned
trace = 0 trace = 0
def __init__(self, lexicon, stream, name = ''): def __init__(self, lexicon, stream, name = '', initial_pos = None):
""" """
Scanner(lexicon, stream, name = '') Scanner(lexicon, stream, name = '')
...@@ -84,6 +84,8 @@ class Scanner: ...@@ -84,6 +84,8 @@ class Scanner:
self.cur_line_start = 0 self.cur_line_start = 0
self.cur_char = BOL self.cur_char = BOL
self.input_state = 1 self.input_state = 1
if initial_pos is not None:
self.cur_line, self.cur_line_start = initial_pos[1], -initial_pos[2]
def read(self): def read(self):
""" """
......
compiled = False
def empty_decorator(x):
return x
def locals(**arg_types):
return empty_decorator
def cast(type, arg):
# can/should we emulate anything here?
return arg
def sizeof(arg):
# can/should we emulate anything here?
return 1
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
# Void cython.* directives (for case insensitive operating systems).
from Shadow import *
...@@ -2,5 +2,11 @@ ...@@ -2,5 +2,11 @@
# Cython -- Main Program, generic # Cython -- Main Program, generic
# #
from Cython.Compiler.Main import main if __name__ == '__main__':
main(command_line = 1)
from Cython.Compiler.Main import main
main(command_line = 1)
else:
# Void cython.* directives.
from Cython.Shadow import *
...@@ -100,7 +100,9 @@ setup( ...@@ -100,7 +100,9 @@ setup(
], ],
# pyximport # pyximport
py_modules = ["pyximport/pyximport", "pyximport/pyxbuild"], py_modules = ["pyximport/__init__",
"pyximport/pyximport",
"pyximport/pyxbuild"],
**setup_args **setup_args
) )
cdef struct point:
double x
double y
double z
cdef foo(int, int i,
list, list L,
point, point p, point* ps)
print sizeof(point*)
cdef foo(int i0, int i, list L0, list L, point p0, point p, point* ps):
pass
cdef class A:
cdef list
cdef list L
# Possibly empty declarators
cdef point(self, int, int i, list, list L, point, point p, point* ps):
pass
cdef class B(A):
cdef point(self, o, int i, oo, list L, ooo, point p, point* ps):
pass
cdef point P
cdef point *Ps
cdef A a
foo(2, 3, [], [], P, P, &P)
a.point("something", 3, "anything", [], "an object", P, &P)
...@@ -10,7 +10,7 @@ cdef class Grail: ...@@ -10,7 +10,7 @@ cdef class Grail:
pass pass
_ERRORS = u""" _ERRORS = u"""
1:9: Non-default argument follows default argument 1:10: Non-default argument follows default argument
9:16: This argument cannot have a default value 9:16: This argument cannot have a default value
4:23: Non-default argument following default argument 4:23: Non-default argument following default argument
""" """
...@@ -4,7 +4,5 @@ def f(): ...@@ -4,7 +4,5 @@ def f():
cdef object[e_bufaccess_pxd.T] buf cdef object[e_bufaccess_pxd.T] buf
_ERRORS = u""" _ERRORS = u"""
3:17: Syntax error in ctypedef statement 3:9: 'nothing' is not a type identifier
4:31: 'T' is not a type identifier
4:31: 'T' is not declared
""" """
def f():
cdef float flt1, flt2, flt3
flt1 = flt2 % flt3 # error
_ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_modop.pyx:3:13: Invalid operand types for '%' (float; float)
"""
def f(): def f():
a = <foao>x a = <foao>True
_ERRORS = """ _ERRORS = """
2:13: Unknown type 2:9: 'foao' is not a type identifier
""" """
\ No newline at end of file
...@@ -48,7 +48,7 @@ __doc__ = ur""" ...@@ -48,7 +48,7 @@ __doc__ = ur"""
'with_doc_2(a, b, c)\n\n Existing string\n ' 'with_doc_2(a, b, c)\n\n Existing string\n '
>>> types.__doc__ >>> types.__doc__
'types(Ext a, int b, unsigned short int c, float d, e)' 'types(Ext a, int b, unsigned short c, float d, e)'
>>> print (f_c.__doc__) >>> print (f_c.__doc__)
f_c(char c) -> char f_c(char c) -> char
...@@ -61,13 +61,13 @@ __doc__ = ur""" ...@@ -61,13 +61,13 @@ __doc__ = ur"""
>>> print (f_s.__doc__) >>> print (f_s.__doc__)
f_s(short int s) -> short int f_s(short s) -> short
>>> print (f_us.__doc__) >>> print (f_us.__doc__)
f_us(unsigned short int s) -> unsigned short int f_us(unsigned short s) -> unsigned short
>>> print (f_ss.__doc__) >>> print (f_ss.__doc__)
f_ss(signed short int s) -> signed short int f_ss(signed short s) -> signed short
>>> print (f_i.__doc__) >>> print (f_i.__doc__)
...@@ -81,23 +81,23 @@ __doc__ = ur""" ...@@ -81,23 +81,23 @@ __doc__ = ur"""
>>> print (f_l.__doc__) >>> print (f_l.__doc__)
f_l(long int l) -> long int f_l(long l) -> long
>>> print (f_ul.__doc__) >>> print (f_ul.__doc__)
f_ul(unsigned long int l) -> unsigned long int f_ul(unsigned long l) -> unsigned long
>>> print (f_sl.__doc__) >>> print (f_sl.__doc__)
f_sl(signed long int l) -> signed long int f_sl(signed long l) -> signed long
>>> print (f_L.__doc__) >>> print (f_L.__doc__)
f_L(long long int L) -> long long int f_L(long long L) -> long long
>>> print (f_uL.__doc__) >>> print (f_uL.__doc__)
f_uL(unsigned long long int L) -> unsigned long long int f_uL(unsigned long long L) -> unsigned long long
>>> print (f_sL.__doc__) >>> print (f_sL.__doc__)
f_sL(signed long long int L) -> signed long long int f_sL(signed long long L) -> signed long long
>>> print (f_f.__doc__) >>> print (f_f.__doc__)
......
__doc__ = """
>>> fmod(7, 1.25)
0.75
"""
def fmod(double a, double b):
return a % b
__doc__ = u"""
>>> test_all()
True
"""
cdef class A:
pass
def test_all():
# Optimized tests.
assert isinstance(type('a',(),{}), type)
assert isinstance(bool(), bool)
assert isinstance(int(), int)
assert isinstance(long(), long)
assert isinstance(float(), float)
assert isinstance(complex(), complex)
assert isinstance(bytes(), bytes)
assert isinstance(str(), str)
assert isinstance(unicode(), unicode)
assert isinstance(tuple(), tuple)
assert isinstance(list(), list)
assert isinstance(dict(), dict)
# if py_ver > (2, 3):
# assert isinstance(set(), set)
assert isinstance(slice(0), slice)
assert isinstance(A, type)
assert isinstance(A(), A)
assert not isinstance("foo", int)
# Non-optimized
foo = A
assert isinstance(A(), foo)
assert isinstance(0, (int, long))
assert not isinstance("xyz", (int, long))
return True
__doc__ = """
sage: get_locals(1,2,3)
{'args': (2, 3), 'kwds': {}, 'x': 1, 'y': 'hi', 'z': 5}
"""
def get_locals(x, *args, **kwds):
y = "hi"
cdef int z = 5
return locals()
...@@ -11,4 +11,9 @@ def f(): ...@@ -11,4 +11,9 @@ def f():
i = sizeof(p) i = sizeof(p)
i = sizeof(j + k) i = sizeof(j + k)
i = sizeof(int) i = sizeof(int)
i = sizeof(long int)
i = sizeof(void*)
i = sizeof(Spam) i = sizeof(Spam)
i = sizeof(Spam*)
i = sizeof(Spam[5])
i = sizeof(Spam (*)())
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